Voice UI
VoiceOrb and PhoneMic — animated voice state indicators and the full-screen phone-style microphone interface.
Overview
Luna has two voice UI components. VoiceOrb is a compact animated indicator that can be embedded anywhere. PhoneMic is the full-screen voice interaction view shown when the user activates phone mode.
| Component | File | Use case |
|---|---|---|
VoiceOrb | components/Voice/VoiceOrb.tsx | Embedded in ChatWindow; also used in the dashboard header. |
PhoneMic | components/Voice/PhoneMic.tsx | Full-screen voice interface triggered from the sidebar. |
VoiceOrb
An animated dual-ring orb that reflects the current voice pipeline state. Outer and inner rings rotate at speeds keyed to the state; a pulse scale animation gives visual feedback during speaking.
interface VoiceOrbProps {
size?: number // diameter in px — default 36
showLabel?: boolean // show status subtitle below the orb
onToggle?: () => void // override the default voice-toggle action
}import { VoiceOrb } from './components/Voice/VoiceOrb'
// Compact mode in the chat header
<VoiceOrb size={28} />
// Larger with subtitle label
<VoiceOrb size={56} showLabel />State sync
VoiceOrb opens a persistent SSE connection to GET /api/voice/eventsand updates its state whenever the backend sends a voice_state event. It polls GET /api/voice/state on mount to set the initial state.
Voice states
| State | Label | Visual |
|---|---|---|
idle | voice off | Static — no rotation, no pulse. |
listening | sleeping | Static — wake-word detection mode. |
followup | listening... | Slow outer rotation, gentle pulse. |
active | listening... | Fast rotation, strong pulse. |
processing | thinking... | Medium rotation, rhythmic pulse. |
speaking | speaking... | Rapid rotation, large pulse (scale 1.22). |
The backend controls state transitions. The frontend only reflects what it receives via SSE — it never sets voice state directly.
PhoneMic
A full-screen voice interaction view styled like a phone call UI. Shows a large VoiceOrb, the current transcript, Luna's response, and controls to end the call. Activated from the sidebar by switching to the voice view.
Key interactions:
- Tap the orb to toggle listening on/off.
- Luna's streamed text response appears below the orb in real-time.
- A waveform animation plays during speech.
- End-call button returns to the chat view and stops the voice pipeline.
import { PhoneMic } from './components/Voice/PhoneMic'
// Shown when activeView === 'voice' in the store
{activeView === 'voice' && <PhoneMic />}Voice endpoints
| Endpoint | Method | Description |
|---|---|---|
/api/voice/state | GET | Current voice state string. |
/api/voice/events | GET (SSE) | State change stream — sends voice_state events. |
/api/voice/toggle | POST | Toggle voice pipeline on/off. |
/api/voice/stream | POST | Submit audio data for processing. |