# Calls (Video Mode) — Deep Dive Calls let the user talk to the assistant hands-free while it *sees* them (webcam) and their screen (screen share). There is ONE call engine — continuous listening, auto-submitted utterances, forced read-aloud TTS, frame capture — entered through four presets that differ only in starting devices. This doc covers the product flow, the technical pipeline, and the LLM prompt surface with exact pointers. ## Product flow The composer has a **call split-button** (`chat-input-with-mentions.tsx`). The main click is the "work together" default — preset `share`: screen sharing ON, camera OFF, floating pill, so the user keeps working while the assistant watches along (the button tooltip discloses the screen share). The chevron menu holds the deviations. While a call is live the button turns red and ends it. | Preset | Starting devices | First surface | |--------|------------------|---------------| | `share` — main click | screen on, camera off | floating pill | | `voice` — "Voice call" | camera off, screen off | floating mascot pill | | `video` — "Video call" | camera on | full-screen call | | `practice` — "Practice session" | camera on, + coaching persona | full-screen call | **One surface rule** (`callSurface` in `App.tsx`): full screen and screen sharing are mutually exclusive in both directions — a full-screen call covers the screen, so sharing it would show the call itself. - sharing → floating popout, always (pill = working) - not sharing → full screen unless `callMinimized` (full screen = facing each other) - expanding the pill auto-STOPS any share; minimizing the full-screen call auto-STARTS one (the pill exists to work together) — presenting from full screen likewise collapses to the pill - the camera toggle never changes the surface: turning it on from the pill puts your video IN the pill; expanding is its own explicit action **Screen-share consent** is three-layered: a toast the moment any share starts ("Your screen is being shared… [Stop sharing]"), a persistent "Sharing screen" badge on the pill, and macOS's purple recording indicator. If the auto-share fails (Screen Recording permission not granted) the call starts anyway as a voice call, with a toast linking to System Settings. Practice/coaching is always an explicit choice — expanding to full screen never turns the coach on. In-call controls (identical bar on both surfaces): mic mute, camera toggle (silhouette avatar while off, no webcam frames captured), screen share toggle, mascot ⇄ "R" letter avatar, end call. **Mute is a full input pause**, not just audio — mic audio stops reaching Deepgram (`useVoiceMode.setPaused`, OR'd with the automatic thinking/speaking pause) AND camera/screen frame capture stops (`useVideoMode.setCapturePaused`; `collectFrames()` returns nothing while muted, so typed messages carry no frames either), letting the user talk to someone in the room without the assistant listening in. Devices stay acquired for instant unmute (camera light and macOS share indicator stay on — the pill's share badge switches to "Sharing paused"), the status chip shows "Muted" instead of "Listening", and assistant output is unaffected (in-flight speech keeps playing; Stop handles that). Mute resets to off at call start/end. While the assistant is thinking or speaking, a red **Stop** button appears on the mascot tile — it silences TTS instantly, skips queued voice segments, and aborts the run if it's still generating (stopping a run from anywhere, including the composer, also silences TTS). Captions of the in-progress utterance and the assistant's spoken line run along the bottom. Typing in the composer still works mid-call; frames ride along with typed messages too. Outside calls the composer keeps exactly one voice affordance: the **mic button** (push-to-talk dictation, untouched). Spoken responses exist only inside calls (forced full read-aloud, off on hang-up). The old video dropdown, talking-head toggle, read-aloud headphones toggle, and summary/full TTS dropdown are all retired — a per-message "read aloud" action on assistant messages is the planned replacement for text-in/voice-out. The call button is disabled unless both voice input (Deepgram) and voice output (TTS) are configured. `call_started` (with `preset`) is captured in PostHog — the adoption metric for this feature. **Popout mechanics**: a small always-on-top frameless window (camera tile when on + mascot tile, live caption, control bar) floating over every app — including Rowboat. Control-bar actions round-trip `video:popoutAction` → main → `video:popout-action` → app window, which owns the mic/camera/capture; `expand` also refocuses the app window (handled in main). ## Frame pipeline `apps/renderer/src/hooks/useVideoMode.ts` runs one capture pipe per source (stream → offscreen `