> ## Documentation Index
> Fetch the complete documentation index at: https://songbird.studiocollective.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Songbird React UI (`react_ui/src/`)

# Songbird React UI (`react_ui/src/`)

The React frontend provides the full DAW interface for Songbird, running inside a Tauri WebView. Built with Vite, React 19, Tailwind CSS v4, and Zustand for state management.

## Architecture Overview

```
┌─────────────────────────────────────────────────────────┐
│  App.tsx                                                 │
│  ├─ Transport          — top bar: play/stop/BPM/scale    │
│  ├─ ArrangementView    — timeline with track lanes       │
│  ├─ ChatPanel          — AI assistant sidebar            │
│  ├─ HistoryPanel       — git commit history              │
│  ├─ BirdFilePanel      — .bird file text editor          │
│  ├─ MidiEditor         — piano roll + velocity lane      │
│  ├─ SampleEditor       — audio waveform display          │
│  ├─ SheetMusicView     — notation rendering              │
│  ├─ GuitarTabView      — guitar tablature                │
│  ├─ MixerPanel         — channel strips + master         │
│  ├─ ScriptFXEditorPanel— DSP script editor               │
│  ├─ CustomEditorPanel  — stock plugin UI host            │
│  ├─ CollabCursors      — multiplayer cursors             │
│  ├─ SettingsPanel      — audio/MIDI/UI settings          │
│  ├─ DebugPanel         — dev tools overlay               │
│  └─ StatusBar          — bottom strip + ExportStatusIndicator │
└─────────────────────────────────────────────────────────┘
```

## Component Structure (Atomic Design)

```
components/
├── atoms/          — Primitive UI elements (Button, Knob, Slider, Select, etc.)
├── molecules/      — Composed units (LevelMeter, PluginSlots, MuteSoloButtons, etc.)
├── organisms/      — Larger composed blocks (MixerChannel, MasterChannel, TrackLane, etc.)
└── panels/         — Full panel/page-level components (ArrangementView, MidiEditor, etc.)
```

### Atoms (`atoms/`)

Reusable primitives built on Radix UI. Styled with Tailwind + `class-variance-authority`:

* `button`, `input`, `select`, `slider`, `knob`, `switch`, `tabs`, `toast`, `tooltip`, etc.
* `RotaryKnob` — Rotary parameter knob with arc visualization, used across all stock plugin UIs
* `ADSRView` — Interactive ADSR envelope editor with drag handles
* `AudioWaveform` — Audio waveform display component
* `SessionClipSlot` — Clip slot for session/performance view
* `CodeEditor` — CodeMirror-based text editor (used by ScriptFX and BirdFilePanel)

### Molecules (`molecules/`)

Composed components combining multiple atoms:

* `LevelMeter` — per-track audio level visualization
* `PluginSlots` — instrument/FX/strip slot management
* `MuteSoloButtons`, `PanControl`, `VolumeFader` — mixer controls
* `StereoMeters` — spectrum, stereo width, phase correlation meters
* `RecordStrip` — MIDI/audio recording controls per track
* `PluginShell` / `PluginHeader` / `PluginBody` / `PluginSection` — shared layout components for stock plugin UIs
* `EditorPanelShell` — container shell for custom editor panels

### Organisms (`organisms/`)

Larger self-contained UI blocks:

* `MixerChannel` / `MasterChannel` — full channel strips
* `TrackHeader` / `TrackLane` — arrangement view rows
* `TimelineRuler` — bar/beat ruler
* `GenerateInlinePopup` — Option+click-drag inline AI generation overlay
* `LoadingScreen` — first-load overlay; `ExportStatusIndicator` — inline progress widget mounted in `StatusBar`

## State Management

### Zustand Stores (`data/`)

Stores are organized to mirror Rust's `StateManager` slices (10 domain slices).
Types live in their canonical domain module and are re-exported from `mixer.ts`
for backward compatibility.

| Store                    | Rust Slice        | Purpose                                                            |
| ------------------------ | ----------------- | ------------------------------------------------------------------ |
| `useTransportStore`      | `TransportSlice`  | Playback position, BPM, key signature, scale, loop state           |
| `useMixerStore`          | `MixerSlice`      | Track list (denormalized), volumes, pans, mutes, solos             |
| `useSongStore`           | `SongSlice`       | Song structure: sections, totalBars                                |
| `useClipStore`           | `ClipSlice`       | (types: NoteData, AudioClip, TakeLane — data in Track for now)     |
| `usePluginStore`         | `PluginSlice`     | (types: PluginSlotView, MissingPluginInfo — data in Track for now) |
| `useRecordingStore`      | `RecordingSlice`  | (types: AudioSource, MonitoringMode — data in Track for now)       |
| `useAutomationStore`     | `AutomationSlice` | (types: AutomationPoint, AutomationCurve — data in Track for now)  |
| `useSettingsStore`       | `SettingsSlice`   | User preferences (global, not per-project)                         |
| `useChatStore`           | `AiSlice`         | AI chat messages, threads, right panel state                       |
| `useLyriaStore`          | `AiSlice`         | AI music generation config                                         |
| `useGenerateStore`       | `AiSlice`         | AI generation state                                                |
| `useCustomEditorStore`   | `ProjectSlice`    | Custom MIDI editor definitions                                     |
| `useScriptFxEditorStore` | `ProjectSlice`    | Script FX editor definitions                                       |
| `useNotesStore`          | `ProjectSlice`    | Panel notes attached to views                                      |
| `useUIStore`             | (ephemeral)       | Panel toggles, editor state, clip selection, drag state            |
| `useInlineGenerateStore` | (client-only)     | Inline AI generation state: drag region, progress, results         |

#### Domain Type Modules

Types are defined in their canonical domain module and re-exported from
`mixer.ts` for backward compatibility:

| Module                 | Types                                                                                            |
| ---------------------- | ------------------------------------------------------------------------------------------------ |
| `slices/clip.ts`       | `NoteData`, `AudioClip`, `TakeLane`, `ClipSelection`, `ClipClipboard`                            |
| `slices/plugin.ts`     | `PluginSlotView`, `PluginInstance`, `MissingPluginInfo`, `PluginSubstitution`, `AvailablePlugin` |
| `slices/recording.ts`  | `MonitoringMode`, `ArmState`, `AudioSource`, `AudioMode`, `MidiInput`                            |
| `slices/automation.ts` | `AutomationPoint`, `AutomationCurve`                                                             |
| `slices/song.ts`       | `Section`                                                                                        |

#### Domain Selector Hooks (`data/hooks/useTrackDomain.ts`)

Per-track domain hooks provide render isolation via `useShallow`:

| Hook                     | Domain     | Fields                                |
| ------------------------ | ---------- | ------------------------------------- |
| `useTrackSong(id)`       | Song       | name, type, color, isReturn, isMaster |
| `useTrackMixer(id)`      | Mixer      | volume, pan, muted, solo, sends       |
| `useTrackClips(id)`      | Clip       | notes, audioClips, takeLanes          |
| `useTrackPlugins(id)`    | Plugin     | instrument, fxSlots, channelStrip     |
| `useTrackRecording(id)`  | Recording  | recordArmed, audioSource, monitorMode |
| `useTrackAutomation(id)` | Automation | automation curves                     |

### Event-Only Hydration

Zustand stores are pure UI caches — no persistence middleware. Rust pushes initial state via events on startup (`settings.react_ready`), and all runtime updates flow through the same event path:

```
Rust engine change
  → ctx.send(eventName, json)
  → Tauri event / WebSocket message
  → sync engine subscriber
  → useMixerStore.setState() / useSongStore.setState() / etc.
  → addStateListener callback
  → Zustand setState() (partial merge)
```

### Key Event Channels

| Event                          | Direction   | Description                                                                                                                                                                  |
| ------------------------------ | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `meters:rt_frame`              | Rust → JS   | Batched real-time data at 30Hz: per-track levels, master levels, transport position, spectrum, stereo analysis, CPU stats. JS-side ballistic smoothing provides visual 60Hz. |
| `track:state`                  | Rust → JS   | Full track/section/note data after .bird load                                                                                                                                |
| `track:notes_changed`          | Rust → JS   | Lightweight note update from MIDI editing                                                                                                                                    |
| `mixer:track_update`           | Rust → JS   | Per-track volume/pan/mute/solo                                                                                                                                               |
| `project:loading_progress`     | Rust → JS   | Loading progress messages during startup                                                                                                                                     |
| `project:bird_content_changed` | Rust → JS   | Notifies BirdFilePanel of .bird file content changes                                                                                                                         |
| `collabCursorUpdate`           | Server → JS | Collaborator cursor position updates (via WebSocket)                                                                                                                         |
| `collabPresence`               | Server → JS | User join/leave events for the collaboration room                                                                                                                            |
| `ai:inline_generate_progress`  | Rust → JS   | Progress updates during inline AI audio/MIDI generation                                                                                                                      |

## Key Libraries

* **React 19** — UI framework
* **Tailwind CSS v4** — Utility-first styling (via `@tailwindcss/vite` plugin)
* **Zustand** — Lightweight state management
* **Radix UI** — Accessible primitive components
* **class-variance-authority** — Component variant styling
* **@tonaljs** — Music theory calculations (chord, note, tonal)

## Development

```bash theme={null}
cd react_ui
npm install
npm run dev      # Vite dev server (for standalone development)
npm run build    # Production build (output to dist/, served by Tauri WebView)
```

> **Note:** In production, the React app runs inside the Tauri WebView — not a browser. The `window.__SONGBIRD__` global is injected by the Tauri bridge and provides the backend event system. All commands go through `send()` from `@/sync/api` or `invoke()` from `@/sync/transports/promiseHandler`.
