Skip to content

johnrbell/jazzhands

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

38 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

JazzHands

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.

JazzHands Demo

Requirements

  • macOS 13.0+
  • Xcode 15+ or Swift 5.9+
  • Accessibility permission (prompted on first launch)

Build & Run

With Swift Package Manager:

swift build
.build/debug/JazzHands

With Xcode:

open JazzHands.xcodeproj

Then build and run the JazzHands scheme (⌘R).

How It Works

Primary JazzHands (Tier 1)

  • 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)

Deep JazzHands (Tier 2)

  • 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

Architecture

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

Permissions

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.

Segment Selection Math

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.

About

tab switcher in a video game menu style

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages