Skip to content

madebysan/wave-ios

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Wave app icon

Wave

Local speech-to-text keyboard for iOS.
Your voice is processed entirely on your iPhone – nothing leaves your device.

Version 1.0.0 · iOS 17.0+ · Apple Silicon

Also available for macOS


How It Works

Wave is a custom iOS keyboard with a dictation button. Tap the mic, speak, and your words appear as text in any app – Messages, Notes, Mail, or anything with a text field.

Unlike cloud-based dictation, Wave runs WhisperKit (OpenAI's Whisper model) entirely on-device. No internet required, no data sent anywhere.

The Flow

  1. Switch to the Wave keyboard (globe icon)
  2. Tap the mic button
  3. Wave app opens and starts recording
  4. Speak, then tap Done
  5. Switch back to your app – text is inserted automatically

Why the App Handoff?

Apple blocks microphone access in all keyboard extensions (privacy policy, not a bug). So Wave uses the same pattern as Wispr Flow and other dictation keyboards: the keyboard launches the main app for recording, then passes the result back through shared storage.

Architecture

┌─────────────────────┐     wave://dictate     ┌─────────────────────┐
│  Keyboard Extension  │ ────────────────────▶  │     Wave App        │
│                      │                        │                     │
│  • Mic button        │     App Group          │  • AVAudioEngine    │
│  • Status display    │ ◀──────────────────── │  • WhisperKit       │
│  • Polls for results │   (transcription)      │  • Filler filter    │
│                      │                        │  • History          │
│                      │                        │  • Settings         │
└─────────────────────┘                        └─────────────────────┘

Shared via App Group (group.com.santiagoalonso.wave):

  • Transcription results
  • Dictation state (idle → recording → transcribing → done)
  • Settings (model, language, filler toggle)
  • History

Project Structure

WaveKeyboard/
├── Shared/                          # Code shared between both targets
│   ├── AudioRecorder.swift          # AVAudioEngine recording (main app only)
│   ├── DictationState.swift         # State enum for the pipeline
│   ├── FillerFilter.swift           # Removes um, uh, you know, etc.
│   ├── SharedStorage.swift          # App Group read/write bridge
│   ├── Transcriber.swift            # WhisperKit wrapper (main app only)
│   └── TranscriptionHistory.swift   # JSON history in shared container
│
├── WaveApp/                         # Main app target
│   ├── WaveApp.swift                # @main, deep link handler
│   ├── ContentView.swift            # Home screen + setup instructions
│   ├── DictationView.swift          # Recording + transcription UI
│   ├── OnboardingView.swift         # First-run setup wizard
│   ├── SettingsView.swift           # Model, language, filler, history
│   └── HistoryView.swift            # Past transcriptions
│
├── WaveKeyboardExtension/           # Keyboard extension target
│   ├── KeyboardViewController.swift # UIInputViewController + polling
│   └── KeyboardView.swift           # SwiftUI keyboard UI
│
└── project.yml                      # XcodeGen spec

Setup

Requirements

  • Xcode 16+
  • iOS 17.0+ device (Simulator works for UI, but keyboard extensions need a real device)
  • XcodeGen (brew install xcodegen)

Build

cd WaveKeyboard
xcodegen generate
open WaveKeyboard.xcodeproj

Set your development team in Signing & Capabilities for both targets, then build and run on your iPhone.

Enable the Keyboard

  1. Settings → General → Keyboard → Keyboards → Add New Keyboard → Wave
  2. Tap Wave in the list → enable Allow Full Access
  3. In any text field, long-press the globe/emoji button → select Wave

Configuration

Setting Default Options
Speech model base (~140 MB) tiny, base, small
Detect language Auto-detect auto + 9 languages
Output language Original Original, English (translate)
Filler removal On On/Off
Copy to clipboard On On/Off
History On On/Off

Shared with macOS Wave

This project reuses core logic from the macOS Wave menu bar app:

File Reuse Changes
FillerFilter.swift ~100% Reads settings from SharedStorage instead of UserDefaults
Transcriber.swift ~90% os.Logger, parameterized model/language, @Published state
AudioRecorder.swift ~85% Added AVAudioSession setup, audio level publishing
TranscriptionHistory.swift Logic Rewritten for App Group container

Feedback

Found a bug or have a feature request? Open an issue.

License

MIT


Made by santiagoalonso.com

About

Local speech-to-text keyboard for iOS. Your voice is processed entirely on your iPhone.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages