Skip to main content

Songbird React UI (react_ui/src/)

The React frontend provides the full DAW interface for Songbird, running inside a JUCE 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          │
│  ├─ MixerPanel         — channel strips + master         │
│  ├─ SettingsPanel      — audio/MIDI/UI settings          │
│  ├─ DebugPanel         — dev tools overlay               │
│  └─ ExportProgressModal                                  │
└─────────────────────────────────────────────────────────┘

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.

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

Organisms (organisms/)

Larger self-contained UI blocks:
  • MixerChannel / MasterChannel — full channel strips
  • TrackHeader / TrackLane — arrangement view rows
  • TimelineRuler — bar/beat ruler
  • LoadingScreen / ExportProgressModal — overlays

State Management

Zustand Stores (data/)

StoreIDPurpose
useTransportStoresongbird-transportPlayback position, BPM, key signature, scale, loop state
useMixerStoresongbird-mixerTrack list, volumes, pans, mutes, solos, notes, sections, plugins
useChatStoresongbird-chatAI chat messages, threads, right panel state
useLyriaStoresongbird-lyriaAI music generation config

State Persistence Bridge (data/bridge.ts)

All Zustand stores persist through a custom StateStorage that routes to C++ via JUCE native functions:
React setState()
  → Zustand persist middleware
  → juceBridge.setItem(storeName, JSON)
  → C++ updateState native function
  → C++ handleStateUpdate() applies to engine
C++ pushes state back via WebView events:
C++ engine change
  → webView->emitEventIfBrowserIsVisible(eventName, json)
  → addStateListener callback
  → Zustand setState() (partial merge)

Key Event Channels

EventDirectionDescription
rtFrameC++ → JSBatched real-time data at 30Hz: per-track levels, master levels, transport position, spectrum, stereo analysis, CPU stats. JS-side ballistic smoothing provides visual 60Hz.
trackStateC++ → JSFull track/section/note data after .bird load
notesChangedC++ → JSLightweight note update from MIDI editing
trackMixerUpdateC++ → JSPer-track volume/pan/mute/solo from ValueTree listeners
loadingProgressC++ → JSLoading progress messages during startup
birdContentChangedC++ → JSNotifies BirdFilePanel of .bird file content changes

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

cd react_ui
npm install
npm run dev      # Vite dev server (for standalone development)
npm run build    # Production build (output to dist/, served by JUCE WebView)
Note: In production, the React app runs inside the JUCE WebView — not a browser. The window.__JUCE__ global is injected by JUCE and provides the native function bridge.