Songbird React UI (react_ui/)
The React frontend provides the full DAW interface for Songbird. It runs inside a Tauri v2 WebView (not a regular browser) and communicates with the Rust backend through the sync engine — a single typed dispatch (songbird_sync::dispatch) that all UI ↔ backend traffic flows through. The same UI also runs against a headless Rust WebSocket server for browser-based e2e tests and the WASM build for the web app.
Tech Stack
- React 19 — UI framework
- Vite — Build tool with
@vitejs/plugin-react-swc - TypeScript — Type safety
- Tailwind CSS v4 — Utility-first styling (via
@tailwindcss/vite) - Zustand — Lightweight state management with persistence
- Radix UI — Accessible primitive components
- class-variance-authority — Component variant styling
- @tonaljs — Music theory (chords, notes, scales)
- @codemirror — Code editor (ScriptFX, BirdFilePanel)
Project Structure
Build & Development
The preferred workflow is./utils/build-rs from the repo root, which boots the Vite dev server and the Tauri shell together with HMR. The raw npm scripts still work:
Important: In production, the React app runs inside Tauri v2’s WebView (or, forsongbird-headless/songbird-wasm, against a Rust WebSocket server). All backend calls go through the sync engine —send()/sendRT()from@/sync/api. Direct Tauriinvoke()is reserved for OS dialogs only (see Hard Rule #1 inCLAUDE.md).
Backend communication
A single typed pipeline carries every UI ↔ backend message:- Commands —
send('channel.action', payload)from@/sync/api. High-frequency knob/slider drags usesendRT(...)to skip guards and echo suppression. - Events — incoming events are subscribed in
@/sync/wiring.tsand the per-channelevents.tsmodules, then mirrored into Zustand stores. - Transports — Tauri IPC in desktop, WebSocket in headless/web, in-process dispatch in WASM. All three share the same
dispatchAPI. - Persistence — settings that must survive a reload live in a sync-engine channel with its own
PersistenceStrategy. NeverlocalStorageor Zustand’spersistmiddleware.
Key Conventions
- Atomic Design: Components organized as atoms → molecules → organisms → panels
- Tailwind-only styling: No CSS modules or styled-components. Use
cn()from@/lib/utilsfor conditional classes - Zustand for state: Never use React Context or prop drilling for shared state
- Direct DOM for meters: High-frequency visuals (level meters, playheads) use
subscribeRtBuffer()+ direct DOM manipulation, bypassing React’s render cycle - Path aliases:
@/maps tosrc/(configured intsconfig.app.json)
Testing
The React UI uses Vitest for unit testing. Test files live alongside the code they test (e.g.,data/slices/mixer.test.ts).
- Zustand store slices (
chat.test.ts,generate.test.ts,mixer.test.ts,transport.test.ts) - Store integration tests (
store.test.ts) - Utility tests (
sliderDrag.test.ts)
Recent Additions
- Inline AI Generation — Option+click-drag on arrangement tracks to generate audio (Lyria) or MIDI directly at a position. Uses
GenerateInlinePopuporganism andinlineGenerateslice. - Collaboration —
CollabCursorscomponent renders Figma-style multiplayer cursors.CollabPanelshows connected users and invite codes.collabMixerSync.tsprovides optimistic mixer state sync. - Stock Plugin UIs — Premium-quality plugin editors in
components/plugins/using sharedPluginShell/PluginBody/PluginSectionlayout components andRotaryKnob/ADSRViewatoms. - ScriptFX Editor —
ScriptFXEditorPanelprovides a CodeMirror-based editor for writing DSP scripts (JavaScript or Faust/WASM). - Sheet Music & Guitar Tabs —
SheetMusicViewandGuitarTabViewpanels for rendered notation and tablature. - Specialized AI Agents — Composer, mix engineer, sound designer, and audio creator agents in
lib/ai/agents/with intent-based routing. - Custom Editor Framework —
CustomEditorPanelandEditorPanelShellin panels, withcustomEditorsslice for managing which plugin UIs to render.
Error Tracking
Sentry integration is initialised insentry.ts for the WebView layer. The Rust side runs its own sentry crate integration (activated by the analytics channel — see rust/crates/data/songbird-analytics/); both feed into the same project.