A macOS window manager inspired by Divvy.
Open a floating panel, drag across a grid to define any region, and snap the frontmost window into place instantly.
- Floating panel — Opens on launch and via the menu bar; shows the target app's icon and name
- Grid drag selection — Drag across a 6×4 grid to define any region, then release to snap
- Local shortcuts — Assign key combos that fire while the panel is open (no system-wide conflicts)
- Optional global hotkey — Optionally bind a global key combo to open the panel
- Menu bar app — Runs in the background with no Dock icon
- Liquid Glass UI — Built for macOS 26
- Launch at Login — Toggle from Settings
- macOS 26.0+
- Apple Silicon or Intel
- Xcode 26+
- xcodegen
brew install xcodegengit clone https://github.com/katsuma/snappy.git
cd snappy
make installmake install-system # prompts for sudo passwordBoth commands build the app, copy it to the target directory, register it with LaunchServices, and launch it. Running from ~/Applications or /Applications is required for Accessibility permissions and Launch at Login to work correctly.
make cleanRemoves the app from both ~/Applications and /Applications, and resets Accessibility permissions.
- Launch the app — a menu bar icon appears and the panel opens automatically
- Click the menu bar icon → Settings…
- General tab → click Open System Settings…
- Enable Snappy under Privacy & Security → Accessibility
- The status in Settings updates to "Access granted" within a few seconds
- The panel opens automatically when Snappy launches, or click the menu bar icon → Show Panel
- The panel displays the frontmost app's icon and name as the target
- Drag across the grid to define the region — release to snap the window
- Press Esc or click ✕ to dismiss without snapping
- Click Settings… → Shortcuts tab → New
- Enter a name (e.g.
Left Half) - Drag across the small grid to select the target region
- Click the key recorder and press your desired key combo (e.g.
⌘←)
Open the panel, then press the configured key combo — the target window snaps to the assigned region and the panel closes.
Shortcuts are local to the panel and are not registered system-wide, so they never conflict with other apps' shortcuts.
To open the panel with a global key combo:
- Settings… → General tab → enable Use global shortcut to open panel
- Click the key recorder and press your desired combo
Snappy/
├── App/
│ ├── SnappyApp.swift # @main entry point
│ └── AppDelegate.swift # Menu bar, panel lifecycle, settings window
├── Models/
│ ├── Shortcut.swift # Shortcut data model (name + region + key combo)
│ ├── GridRegion.swift # Grid region (6×4)
│ └── KeyCombo.swift # Key code + Carbon modifier flags
├── Services/
│ ├── SnapPanelManager.swift # Panel window lifecycle, target app tracking
│ ├── HotkeyManager.swift # Optional global hotkey via Carbon RegisterEventHotKey
│ ├── WindowMover.swift # Window move/resize via AXUIElement
│ ├── ShortcutStore.swift # JSON persistence (~/Library/Application Support/Snappy/)
│ └── PanelSettings.swift # Panel hotkey settings (UserDefaults)
└── Views/
├── SnapPanelView.swift # Floating panel (target app header + grid)
├── PreferencesView.swift # Settings window (General + Shortcuts tabs)
├── GeneralView.swift # Accessibility, login item, panel hotkey
├── ShortcutsView.swift # Shortcut list
├── ShortcutRowView.swift # Per-shortcut editor row
├── GridPickerView.swift # 6×4 grid picker (Canvas + DragGesture)
└── KeyRecorderView.swift # Key capture (NSViewRepresentable)
Notable implementation details:
- The panel captures
NSWorkspace.frontmostApplicationandkAXFocusedWindowAttributebefore activating Snappy, so the correct target window is always acquired. When Snappy is already frontmost (e.g. via menu bar click), it falls back to the last observed non-Snappy app tracked viaNSWorkspace.didActivateApplicationNotification. - Local shortcuts use
NSEvent.addLocalMonitorForEventsinstalled while the panel is visible — they are never registered as global hotkeys. - The optional global hotkey uses Carbon's
RegisterEventHotKey+InstallEventHandler. Self is recovered inside the C callback viaUnmanaged. - Window manipulation uses
AXUIElement. Coordinates require a flip: NSScreen uses a bottom-left origin while AX uses the top-left of the primary display. - App Sandbox is disabled — required for both AXUIElement and Carbon hotkeys.
Accessibility permissions are tied to the app's install path and code signature. Always use make install rather than running directly from Xcode's DerivedData — otherwise the app icon won't appear in System Settings and permissions won't stick.
If permissions get out of sync after a rebuild:
make clean && make installMIT

