Files
sst/docs/superpowers/specs/2026-10-01-push-to-talk-dictation-design.md
T
2026-10-01 09:29:49 +02:00

3.9 KiB

Push-to-talk dictatie-app voor macOS — ontwerp

Datum: 2026-10-01 · Status: concept ter review · Werktitel: Sst

Doel

Een systeembrede dictatie-app, vergelijkbaar met Wispr Flow. De gebruiker houdt Fn ingedrukt, spreekt, laat los, en de transcriptie verschijnt op de cursor in elke app. Alles draait lokaal op de Mac. Nederlands en Engels mogen door elkaar gebruikt worden.

Buiten scope (v1)

  • AI-cleanup (vulwoorden, zelfcorrecties, toon per app). Alleen de naad (Cleaner) wordt voorbereid.
  • Streaming-transcriptie tijdens het praten.
  • Mac App Store-distributie, accounts, sync, cloud.
  • Branding. Die volgt als aparte stap na de werkende kern.

Doelomgeving

Apple M4 Pro, 24 GB RAM, macOS 27, Xcode 27, Swift 6.4. Alleen Apple Silicon.

Aannames

  • Persoonlijk gebruik, niet-gesandboxed. De Mac App Store-sandbox verbiedt globale key-taps en gesimuleerd plakken.
  • Niets verlaat de Mac. Audio wordt niet bewaard.
  • Spraakmodel: Whisper large-v3-turbo via WhisperKit, met automatische taalherkenning.

Architectuur

Een macOS-menubalk-app (SwiftUI MenuBarExtra). De logica staat in een Swift Package (testbaar met swift test). De Xcode-app is een dunne schil eromheen.

Unit Taak Afhankelijk van
HotkeyMonitor Detecteert Fn omlaag/omhoog via CGEventTap; stuurt pressed/released events Input Monitoring
AudioRecorder AVAudioEngine neemt op naar een 16 kHz mono Float-buffer; start bij pressed, stopt bij released Microfoon
Transcriber (protocol) transcribe(samples) async throws -> String; eerste implementatie WhisperKitTranscriber WhisperKit
Cleaner (protocol) clean(text, context) async throws -> String; v1 PassthroughCleaner n.v.t.
TextInserter Zet tekst op het klembord, simuleert ⌘V, herstelt het klembord Accessibility
DictationController Statemachine idle → recording → transcribing → inserting → idle; enige component dat de andere kent bovenstaande
OverlayPanel Floating NSPanel met pilletje: opname, golfvorm, bezig SwiftUI
MenuBarExtra Status, instellingen, model-download, rechten-check n.v.t.

Ontwerpprincipes: elke unit heeft één taak en een duidelijke interface. Transcriber en Cleaner zijn protocollen, zodat modellen (bijvoorbeeld Parakeet of een LLM) later verwisselbaar zijn. Tests gebruiken fakes voor de protocollen.

Dataflow

  1. Fn omlaag: opname start, overlay verschijnt.
  2. Fn omhoog: opname stopt.
  3. Samples gaan naar Transcriber, daarna naar Cleaner.
  4. TextInserter voegt de tekst in; overlay verdwijnt.

Het model wordt bij het opstarten geladen en blijft warm in het geheugen.

Foutafhandeling

  • Opname korter dan ~0,3 s: negeren (per ongeluk aangetikt).
  • Rechten ontbreken: menubalk toont wat ontbreekt, met knop naar de juiste Systeeminstellingen.
  • Model nog niet gedownload: eerste start toont voortgang; dictatie is dan uitgeschakeld.
  • Invoegen mislukt: tekst blijft op het klembord, overlay meldt dit.
  • Stilte of lege transcriptie: niets invoegen.
  • Transcriptiefout: overlay toont een korte foutmelding; de controller keert terug naar idle.

Vereiste rechten

Microfoon, Accessibility (plakken simuleren), Input Monitoring (Fn-toets).

Testen

  • Unit-tests voor DictationController met fake Transcriber, Cleaner, TextInserter (toestandsovergangen, korte opnames, foutpaden).
  • Unit-test voor het klembord-herstel in TextInserter (injecteerbare pasteboard).
  • Handmatige rooktest van de hele keten in TextEdit, Notes en een browser: Nederlands, Engels en gemengd.

Bouwvolgorde (skeleton eerst)

  1. Package plus menubalk-app; hotkey logt alleen "recording…".
  2. Opnemen naar een buffer.
  3. WhisperKit transcriberen.
  4. Tekst invoegen.
  5. Overlay-pill.
  6. Cleanup, instellingen en branding (aparte specs).

Open punten

Geen voor het skeleton. De definitieve naam en branding worden in een latere stap bepaald.