Status: ratified — shipped 2026-04-27 (Sources/OpenQuackApp/RecordingOverlay.swift)
Owner: apps/OpenQuack/Sources/Overlay/ (when the app target lands)
Last updated: 2026-04-26
Show a small, non-intrusive floating window that surfaces recording state so the user knows when the mic is hot, when the transcription is running, and when the agent is acting. Privacy-critical: the user must always know we’re listening.
RECORDING (red dot + timer + level meter)
│ stop hotkey
▼
TRANSCRIBING (orange spinner + model name)
│ transcript ready
▼
DISPATCHING (purple, only if non-passthrough agent + network indicator)
│ result returned
▼
DONE (green check, fade out 1s)
CANCELLED (grey, fade out 0.6s) — from any state
ERROR (red banner, dismiss after 4s) — from any state
NSPanel, ~280 × 56 pt, top-centre of the screen, 24 pt below menu bar.NSWindowLevel.floating, click-through (mouse events pass through to apps below).requiresNetwork == true.public enum OverlayState: Sendable {
case hidden
case recording(seconds: Double, level: Float)
case transcribing(modelLabel: String)
case dispatching(agentLabel: String, network: Bool)
case done(message: String)
case cancelled
case error(message: String)
}
@MainActor
public final class OverlayController {
public init()
public func transition(to state: OverlayState)
}
transition(to:). No direct mutation.recording.level) updates at 30 fps; the overlay subscribes to AudioRecorder.currentLevel (SPEC-001).makeKeyAndOrderFront; use orderFront(nil).NSScreen.main. This puts the indicator where the user’s attention already is when they trigger the hotkey.Window or an NSPanel host? NSPanel is more controllable (level, click-through). Lean NSPanel hosting a SwiftUI view via NSHostingView.NSPanel based, similar shape.docs/VISION.md references.