jam-buddy / docs /05-accessibility.md
salgadev's picture
Sync from GitHub 6feaf31d
b2e4883 verified
|
Raw
History Blame Contribute Delete
10.5 kB
# 05 — Accessibility Strategy
## Why this isn't an afterthought
PatternTalk's founder runs [Narwall.tech](https://narwall.tech), an accessibility testing tool that uses a real screenreader to find compliance gaps. The hackathon's Accessibility & Inclusion theme is listed as a first-class track. The target users include blind and visually impaired producers, a population currently locked out of almost every AI music tool.
So accessibility is **load-bearing**, not a checklist. The voice-first design (see [`04-ux-voice-first.md`](04-ux-voice-first.md)) was driven by accessibility, not the other way around.
## Principles
1. **Test with real assistive technology, not just linters.** axe-core catches ~30% of issues. NVDA and VoiceOver catch the rest.
2. **Voice-first is screenreader-first.** Building the voice layer well means the screenreader layer works for free.
3. **Every action has a keyboard equivalent.** No mouse-only paths.
4. **Every pattern has a textual description.** Not an afterthought caption — the description is the data.
5. **No information conveyed by color alone.** The visual grid uses size, position, and label too.
6. **Works at 200% zoom and at high contrast.** Tested with Windows High Contrast Mode.
## Standards we comply with
- **WCAG 2.2 AA** as the floor. AAA where feasible.
- **WAI-ARIA 1.2** for semantic structure.
- **Section 508** (US federal) — implicit via WCAG.
- **EN 301 549** (EU) — implicit via WCAG.
- **VPAT 2.4** — generated for the demo.
## Screenreader support
### Tested screenreaders
| Screenreader | OS | Browser | Status |
|---|---|---|---|
| NVDA 2024.x | Windows | Firefox + Chrome | Primary test target |
| VoiceOver | macOS | Safari | Primary test target |
| JAWS 2024 | Windows | Chrome | Stretch target |
| TalkBack | Android | Chrome | Post-hackathon |
| VoiceOver | iOS | Safari | Post-hackathon |
### Test cadence
- **Before each commit to `main`** that touches the UI: axe-core in CI blocks on AA violations
- **Once per day during the hackathon**: manual NVDA run-through of the full flow
- **Before demo**: NVDA + VoiceOver run-through, both screenshare-able
## Keyboard navigation
Every interactive element is reachable via Tab. Focus order matches visual order. Focus is always visible (high-contrast outline).
```css
:focus-visible {
outline: 3px solid var(--focus-color, #FFD700);
outline-offset: 2px;
}
```
Skip links for repeated UI:
```html
<a href="#main-content" class="skip-link">Skip to main content</a>
<a href="#pattern-grid" class="skip-link">Skip to pattern grid</a>
<a href="#controls" class="skip-link">Skip to controls</a>
```
### Roving tabindex for the visual grid
The grid is a 2D structure. Arrow keys navigate within it; Tab enters/exits.
```typescript
function onGridKeydown(e: KeyboardEvent, row: number, col: number) {
switch (e.key) {
case "ArrowRight": moveFocus(row, col + 1); break;
case "ArrowLeft": moveFocus(row, col - 1); break;
case "ArrowDown": moveFocus(row + 1, col); break;
case "ArrowUp": moveFocus(row - 1, col); break;
case "Home": moveFocus(row, 0); break;
case "End": moveFocus(row, lastCol); break;
case "Enter": announceCurrentCell(); break;
}
}
```
## Voice interaction as accessibility
### How voice maps to screenreaders
When PatternTalk speaks via `SpeechSynthesis`:
- **No screenreader active:** audio plays through speakers, user hears it
- **NVDA active:** NVDA mutes the speech synthesis output and reads the same text via its own voice, using the live region's text content
- **VoiceOver active:** same behavior as NVDA
This is the magic: a single voice output layer works for everyone.
### How STT maps to screenreaders
Screenreaders don't expose their STT input to web pages. So:
- **Sighted users without screenreader:** use Web Speech API STT
- **Screenreader users:** type into a regular text input, or use their screenreader's voice control (e.g., Dragon, Voice Access on Android, Voice Control on macOS)
Both paths converge on the same prompt parser. The UI offers both visibly:
```
[🎤 Hold Space to talk] or [Type a prompt: ____________]
```
### ARIA live regions
When PatternTalk wants to announce something (a new pattern generated, an error, a status change), it uses ARIA live regions:
```html
<div aria-live="polite" aria-atomic="true" id="status">
<!-- PatternTalk writes here when state changes -->
Skank beat, 4 bars at 174 BPM. MIDI ready.
</div>
<div aria-live="assertive" role="alert" id="errors">
<!-- Errors go here, interrupt speechreader -->
</div>
```
**Polite** for routine status (don't interrupt). **Assertive** for errors (interrupt).
## Pattern description format
Every pattern has a screenreader-friendly text description. The format:
```
{Pattern name}. {Genre} at {tempo} BPM.
{Limb-by-limb description}.
{Notable characteristics}.
{Tags/context}.
```
Examples:
**D-Beat:**
```
D-Beat. Metal at 180 BPM. Kick plays on every beat with
8th-note doubles. Snare hits on 2 and 4. Ride bell plays
steady 8th notes throughout. Common in Discharge, Entombed,
and Scandinavian crust punk.
```
**Skank Beat:**
```
Skank Beat. Ska at 120 BPM. Kick on 1 and 3. Snare on
2 and 4. Hi-hat plays on every upbeat — the "and" of each
beat. Ska upstroke feel.
```
**Blast Traditional:**
```
Traditional Blast Beat. Metal at 200 BPM. Kick and snare
alternate in 8th notes throughout. Hi-hat plays continuous
8th notes. High intensity.
```
**Djent Polyrhythm:**
```
Djent Polyrhythm. Metal at 140 BPM. Kick plays a 4-over-3
polyrhythm against the 4/4 pulse. Snare on 2 and 4.
Ride cymbal plays 8th notes. Polyphonic, Meshuggah-style.
```
The description is generated from the template at runtime. Sighted users see it in a panel; screenreaders read it on demand.
## High contrast and theming
```css
:root {
--bg: #ffffff;
--fg: #1a1a1a;
--accent: #0066cc;
--focus: #ffd700;
--limb-kick: #d62828;
--limb-snare: #1d3557;
--limb-hihat: #f4a261;
--limb-ride: #2a9d8f;
--limb-crash: #e76f51;
--limb-china: #8338ec;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #1a1a1a;
--fg: #f0f0f0;
--accent: #66b2ff;
}
}
@media (prefers-contrast: more) {
:root {
--fg: #000000;
--bg: #ffffff;
--accent: #0000ee;
--focus: #ff00ff;
}
}
```
## Reduced motion
Some users get sick from animation. Respect `prefers-reduced-motion`:
```css
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}
```
The visual grid has subtle "pulse" animations when patterns play back. With reduced motion, those are disabled — only color changes indicate playback position.
## Captions and transcripts
Every audio sample generated by SA3 gets a textual caption (derived from the prompt + pattern context):
```
Sample: brutal china crash, 18-inch, trashy.
Duration: 3.0 seconds. Intensity: brutal-max.
```
Captions are:
- Visible by default in the UI
- Read by screenreaders when focus moves to the sample player
- Exportable as a sidecar text file with the .wav download
## CI accessibility checks
```yaml
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
a11y:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- run: npm ci
- run: npm run build
- run: npm run test:a11y # axe-core via @axe-core/playwright
```
`npm run test:a11y` runs Playwright with axe-core against every page. Fails on any WCAG AA violation.
## Manual screenreader test protocol
Before each demo:
1. **Cold start:** Close browser, open PatternTalk, immediately start NVDA
2. **Full flow via keyboard only:** Generate a pattern, audition it, download MIDI, generate variations, pick one, start over
3. **Verify announcements:** Every state change should be announced within 1 second
4. **Verify focus:** Focus should never get stuck or disappear
5. **Verify grid:** Tab to grid, arrow-navigate, every cell announces its limb and velocity
6. **Verify download:** Download MIDI and sample, verify file names announced
7. **Verify errors:** Trigger an error path (e.g., Reaper not running), verify error is announced politely
8. **VoiceOver pass:** Repeat steps 1–7 with VoiceOver on macOS
A short screen recording of this is part of the demo deliverables.
## Reduced-physical-load mode (stretch)
For drummers with RSI, chronic pain, or temporary injury. The plugin generates the physically demanding parts (blast beats, double bass) and the drummer plays the parts they can play.
Implementation: split each pattern into "AI plays" vs "you play" subsets. Export two MIDI tracks. Drummer mutes the AI track they want to play themselves.
Not in scope for the 2-day hackathon, but the data model supports it (each `Hit` has a `playableBy: "ai" | "human"` flag).
## Haptic metronome (stretch)
A paired PWA on the drummer's phone vibrates on the beat. Different vibration patterns for downbeat, backbeat, fills.
Out of scope for the 2-day hackathon. Post-hackathon product.
## Real-time audio captioning (stretch)
Capture audio from the interface, run lightweight audio classification, output live captions: "kick, snare, kick-snare fill, china crash."
Out of scope for the 2-day hackathon. This is what would make the tool usable for deaf producers collaborating with hearing producers.
## Why this matters for the hackathon
Jury includes Andrew Huang, who has explicitly designed for accessibility in past work. Zack Zukowski (Stability AI) is known for caring about inclusive design. The "Accessibility & Inclusion" theme is a first-class track. The MUTEK Festival, where winners present, has an audience that includes accessibility advocates.
A demo that opens with "let me show you the screenreader view" is memorable. A demo that says "and we tested this with NVDA daily" is credible.
## Narwall integration (post-hackathon)
Long-term, PatternTalk could be tested *by* Narwall as part of its workflow — using Narwall's real-screenreader-based testing to continuously verify that no UI regression breaks the screenreader experience. That's a natural fit for the founder's other product and would make PatternTalk the only music tool with continuous accessibility testing baked in.
For the hackathon: mention this as the long-term plan in the demo, don't build the integration.