Find the keyboard, focus, contrast and screen-reader support available in Studio.
Design history: Accessibility and keyboard controls and Native Workbench.
Accessibility differs by shell. The desktop Rust workbench has an AccessKit tree. The browser has a host-owned DOM projection for the active source editor, but does not expose the desktop's complete workbench tree. The editor projection and ordinary DOM product pages do not establish full workbench accessibility parity. Browser implementation and remaining acceptance: Ide Browser Native Parity.
Native desktop workbench#
The native build enables egui's AccessKit integration. Custom-painted controls set roles, names, values, state, and actions instead of relying on their visual shape. Coverage includes workbench chrome, chips/disclosures, sliders and mixing controls, timeline interactions, rack navigation, and editable Bench cells.
The source editor exposes a multiline text input plus TextRun nodes for the lines on screen and the caret's anchor and focus lines (not the whole buffer, so a long song does not rebuild thousands of runs every frame). Runs include text lengths and selection information so assistive technology can navigate the custom rope-backed editor even though it is not an OS text widget. AccessKit identifiers are salted per Bench cell to keep multiple editors distinct.
Keyboard operation includes normal editing/selection, menu commands, focusable controls, structural-editing commands, diagnostics navigation, and configurable UI density. Visible focus and full labels should remain part of every custom widget's acceptance tests.
Shell and transport semantics#
The wide and compact headers expose the same command identities at different placements. Work and contextual destinations are named as destinations with selected state; Show controls are toggles; family and system menus are named disclosures. The native and fallback product menus consume the same registry, including labels, shortcuts, availability, checked state, and disabled reason.
The stable transport rail exposes Run code, Play/Stop, Record, Metronome, Scene, and musical position as distinct controls. Record and Metronome are disclosures rather than ambiguous command chips. When recording is unavailable the control remains named, disabled, and paired with the capability reason; when a recording mode is active its direct stop control exposes that state. Automated AccessKit assertions cover the header target budget, transport presence, record disclosure, and disabled recording state.
Learn and relationship-focus semantics#
Course Continue, lesson choices, and the three lesson presentations use ordinary keyboard-focusable buttons/destinations. Notebook build and Side-by-side share one work buffer; switching presentation does not create an unannounced editor replacement. Further-reading actions carry the humanized document label and return to the invoking lesson.
Track relationship focus is separate from navigation and local surface selection. The Source pin control is a named toggle and supports Alt+P; Timeline, Mixer, and Rack expose the same track name and preview/pinned state. Clearing it changes only that shared relationship. Reduce Motion retains the state through static contrast, so the relationship never depends on animation alone.
Reference workspace semantics#
Reference's Guides/Symbols selectors, Back/Forward controls, return action, search fields, results, the Browse guides list, and the On this page outline use standard egui focusable widgets. Tab and Shift-Tab traverse them; Enter/Space activates the focused button or disclosure. Disabled Back/Forward controls remain named but do not activate.
Guide-search Enter has a two-stage meaning: in grouped results it opens the selected document/topic; in an open Guide it advances to the next highlighted hit and wraps. Document selection is a filterable Browse guides list: category rows are named disclosures, guide rows are selectable, and Enter in the filter opens the first match. In the page outline, each branch's Expand/Collapse button and its heading row are separate controls, so collapsing a parent never changes the current route.
The current AccessKit projection exposes these through their underlying egui button, selectable, text-input, and combo-box semantics. It does not yet promote Guides/Symbols to explicit Tab/TabList roles or the outline to Tree/TreeItem roles. Do not claim those richer roles until focused accessibility-tree tests pin them. The browser canvas limitation below applies to Reference too.
Implementation anchors:
ui/src/editor.rs— text-input node,TextRuns, and text selection;ui/src/docsview.rsandui/src/docsview/navigation.rs— Reference tabs, guide search, Browse guides and the page outline;ui/src/widgets.rs— shared custom-control semantics;ui/src/actions.rsandui/src/app/{header,transport}.rs— canonical command roles, availability, and shell placement;ui/src/focus.rs— generation-fenced preview/pinned relationship state;ui/src/{mixer,timeline,rack,bench,perform}.rs— surface-specific roles and labels;ui/tests/and egui kittest coverage — accessibility-tree assertions.
Browser workbench: source editor projection and remaining gaps#
The browser workbench uses the same Rust/egui canvas UI, but ui/Cargo.toml enables the accesskit feature only on non-wasm targets because the current dependency combination does not support the web runner. The deleted DOM workbench can no longer serve as the fallback assumed by the original native workbench design. The current source editor instead has an operable DOM adapter in runtime/public/studio-a11y.js, mounted beside the canvas.
The adapter exposes a real offscreen textarea, active-file and read-only state, the primary directional selection, structured diagnostics, and a polite status summary. Rust publishes revisioned editor snapshots through ui-wasm/src/web.rs. Text and selection actions return through file-, revision-, and sequence-fenced queues, with explicit acknowledgements. Rust remains the authoritative editor; the DOM adapter does not maintain a separate document implementation.
The current projection covers the active source/import editor, not the entire workbench. Multicaret is projected as the primary selection only. Remaining acceptance in Ide Browser Native Parity Stage 1 includes composition and dictation, real screen-reader clipboard use, import/role transitions, adjacent accessible commands, and recorded VoiceOver/NVDA sessions. Transport, tabs, Mixer, Bench, inspector, dialogs and other canvas controls still require their own accessibility coverage. DOM product pages and editor tests do not prove those panels accessible. Because the canvas has no accessibility tree, a browser drive cannot reach a canvas control through getByRole or a locator: it clicks points, and each click is paired with a post-condition only that control can satisfy, so a moved control fails there rather than as an unrelated timeout later.
Implementation checks live in runtime/src/studio-a11y.test.ts and runtime/scripts/studio-accessibility-browser-test.mjs. The required browser drive (npm --prefix runtime run test:studio-a11y:required) needs freshly built wasm and its documented browser/server prerequisites. Keep missing or skipped browser and manual assistive-technology evidence open.
Product pages#
The notebook, syntax, and lens product pages were deleted 2026-08-21, and the TypeScript workbench's announcer/earcon layer went with the workbench itself. Remaining browser product pages should prefer native HTML controls, labels, landmarks, visible focus, and live regions for asynchronous status.
Release gates#
- Desktop: one editor text/selection assertion and representative custom-control assertions remain green in kittest.
- Browser: accessibility-tree smoke for the DOM projection before claiming screen-reader parity.
- Both: keyboard-only smoke, focus visibility, reduced-motion behavior, and theme contrast at supported densities.
- Documentation and release notes state shell-specific limitations plainly.