A radial app switcher for macOS. Hold a pre-defined key combo to summon a circular ring of your active apps, move the mouse to highlight, and release to switch.
- macOS 13.0+
- Xcode 15+ or Swift 5.9+
- Accessibility permission (prompted on first launch)
With Swift Package Manager:
swift build
.build/debug/JazzHandsWith Xcode:
open JazzHands.xcodeprojThen build and run the JazzHands scheme (⌘R).
- Option + Space (hold): Shows the radial ring of all active apps (apps with at least one visible window)
- Mouse movement: The cursor is hidden and locked to center. Movement direction highlights the corresponding app segment
- Release Option: Switches to the highlighted app and dismisses the UI
- Quick tap: Toggles to the last used app (like a fast Cmd+Tab)
- Hover 500ms on a multi-window app: A second concentric ring appears with window thumbnails
- Move outward into the outer ring to select a specific window
- Release to bring that exact window to front
| File | Purpose |
|---|---|
JazzHandsApp.swift |
SwiftUI app entry point (menu bar agent) |
AppDelegate.swift |
Global hotkey listener, lifecycle management |
WindowManager.swift |
CGWindowList + NSRunningApplication queries |
Models.swift |
JazzHandsApp / JazzHandsWindow data models |
JazzHandsViewModel.swift |
Angle → segment mapping, state machine, hover timers |
JazzHandsView.swift |
SwiftUI radial UI with glow effects |
OverlayWindowController.swift |
Transparent overlay window, mouse locking via CGWarpMouseCursorPosition |
JazzHands requires Accessibility permission to:
- Listen for global hotkeys (Option + Space) when other apps are focused
- Raise specific windows via the Accessibility API
On first launch, macOS will prompt you. You can also enable it manually in System Settings → Privacy & Security → Accessibility.
The mouse vector (dx, dy) from center is converted to an angle:
θ = atan2(dy, dx)
Normalized to [0, 2π), then mapped to a segment index:
index = floor(θ / (2π / n)) % n
where n is the number of active apps.
