Skip to content

Repository files navigation

HyprMac

A keyboard-driven tiling window manager for macOS.

Caps Lock becomes a Hypr modifier key by default, and the physical Hypr key can be changed in Settings. From there: BSP dwindle tiling, 9 virtual workspaces, directional focus and window swapping, drag-to-swap, and focus-follows-mouse — all without touching System Integrity Protection.

HyprMac.Demo.mp4

HyprMac is in active development. Contributions and bug reports are welcome.


What It Solves

macOS doesn't ship with a tiling window manager. Third-party options either require disabling SIP, rely on AppleScript hacks, or bolt tiling on top of macOS Spaces in ways that feel fragile. HyprMac takes a different approach: it manages its own virtual workspaces in userspace, uses Accessibility APIs only, and provides a dedicated Hypr modifier for a clean, Hyprland-style workflow that works within macOS's constraints.


Features

🪟 BSP Dwindle Tiling Smart insertion with min-size adaptation and automatic split ratio adjustment
🗂 9 Virtual Workspaces Managed in userspace — no macOS Spaces dependency, no SIP needed
🎯 Directional Focus & Swap Move focus or swap windows left/right/up/down across monitors
🖱 Focus-Follows-Mouse Toggleable, with automatic suppression when menus are open
🔄 Drag-to-Swap Drag any window onto another to exchange positions
🔲 Floating Toggle Pop windows in and out of the tiling layout on demand
🖥 Multi-Monitor Per-monitor workspace assignment with directional cross-monitor navigation
⌨️ Fully Configurable Edit the Hypr key, keybinds, app launchers, gaps, and padding in-app or via JSON
📋 Keybind Overlay Hypr+K shows all active shortcuts at a glance

Requirements

  • macOS 13 (Ventura) or later
  • Accessibility permission — System Settings → Privacy & Security → Accessibility
  • For the default Caps Lock Hypr key: Caps Lock set to "⇪ Caps Lock" in Modifier Keys (not "No Action")

Installation

Homebrew (recommended)

brew tap zacharytgray/hyprmac
brew install --cask hyprmac

Manual Download

Download the latest DMG from GitHub Releases, open it, and drag HyprMac to Applications.

Build from Source

git clone https://github.com/zacharytgray/HyprMac.git
cd HyprMac

brew install xcodegen
xcodegen generate

export DEVELOPMENT_TEAM=YOUR_TEAM_ID
xcodebuild -project HyprMac.xcodeproj -scheme HyprMac -configuration Debug \
  -derivedDataPath build DEVELOPMENT_TEAM=$DEVELOPMENT_TEAM build

cp -r build/Build/Products/Debug/HyprMac.app /Applications/

Keybinds

All keybinds are configurable in Settings (menubar icon → Settings → Keybinds). The physical Hypr key is configurable in Settings → General. Options include Caps Lock, Tab, backtick, backslash, F13-F20, and left/right variants of Shift, Control, Option, and Command.

Defaults

Shortcut Action
⇪ + ←/→/↑/↓ Focus window in direction
⇪ + ⇧ + ←/→/↑/↓ Swap window in direction
⇪ + J Toggle split direction
⇪ + ⇧ + T Toggle floating/tiling
⇪ + F Cycle focus through floating windows
⇪ + 1–9 Switch to workspace N
⇪ + ⇧ + 1–9 Move window to workspace N
⇪ + ⌃ + ←/→ Move window to adjacent monitor
⇪ + ⇥ / ⇪ + ⇧ + ⇥ Cycle occupied workspaces on current monitor
⇪ + W Close window
⇪ + K Show keybind overlay
⇪ + ↵ Launch/focus Terminal
`⇪ + `` Warp cursor to menu bar

Mouse

Action Effect
Hover over tiled window Focus follows mouse (when enabled)
Drag window onto another Swap positions

Menu Bar Access

Focus-follows-mouse and the macOS menu bar don't always play nicely together — mousing up to the menu bar can accidentally shift focus to a window underneath. HyprMac handles this two ways:

  1. Menu tracking detection — FFM is automatically suppressed while any app's menu is open, so focus won't shift once you've clicked a menu item.
  2. `Hypr + `` — Instantly warps the cursor to the menu bar on the current monitor. It's faster than mousing there manually and sidesteps the focus-switching problem entirely. The action, shortcut, and physical Hypr key are configurable in Settings.

Virtual Workspaces

HyprMac manages 9 workspaces entirely in userspace, bypassing macOS Spaces.

  • Every workspace is statically anchored to a monitor: (N − 1) mod monitorCount, left to right. With 3 monitors, workspaces 1/4/7 live on the left, 2/5/8 in the middle, 3/6/9 on the right
  • Switching to workspace N always lands on its home monitor — workspace identity never drifts between monitors
  • Switching to a workspace that's already visible just focuses its monitor
  • ⇪ + ⌃ + ←/→ throws the focused window to the adjacent monitor's visible workspace
  • Inactive windows are hidden off-screen (a macOS constraint — one pixel remains visible in a corner)
  • Monitor connects/disconnects preserve workspace assignments; layouts migrate to each workspace's current home

A single macOS Space per monitor is recommended for the cleanest experience.


Architecture

HyprMac is structured as a thin orchestration layer over a handful of focused services. Hotkeys feed into an ActionDispatcher that routes work to the right service; a polling loop drives a WindowDiscoveryService that detects new, gone, and drifted windows and hands the diff back to the dispatcher.

HotkeyManager (CGEventTap)
    └→ WindowManager.handleAction
        └→ ActionDispatcher.dispatch
            ├→ FocusStateController       (focus id + visual border)
            ├→ WorkspaceOrchestrator      (workspace switch / move)
            ├→ FloatingWindowController   (toggle / cycle / raise)
            ├→ TilingEngine               (swap / split toggle / retile)
            └→ AppLauncherManager         (launch / focus)
                ↓
        WindowStateCache mutations
                ↓
        TilingEngine.applyLayout (two-pass via FrameReadbackPoller)
                ↓
        FocusBorder, FocusBrackets, DimmingOverlay (visual layer)

Polling and discovery run in parallel:

PollingScheduler (1 Hz timer + coalesced notification triggers)
    └→ WindowDiscoveryService.computeChanges
        └→ ActionDispatcher.applyChanges

Window-keyed state lives in WindowStateCache; focus state in FocusStateController; date-gated suppressions (activation-switch, mouse-focus, cross-swap-in-flight) in SuppressionRegistry. BSP trees live in TilingEngine (one per (workspace, screen) pair) with smart insert backtracking on constrained monitors and two-pass min-size resolution via FrameReadbackPoller.

Everything runs on the main thread. UI-touching classes (FocusBorder, DimmingOverlay, KeybindOverlayController, CursorManager, MouseTrackingManager) assert this in DEBUG via mainThreadOnly().

For deeper reading:


Updating

In-app updates are recommended for most users. HyprMac checks for updates automatically via Sparkle — when one is available, you'll be prompted to install it directly from the app. You can also check manually via the menubar icon → "Check for Updates..."

For Homebrew installs, brew upgrade --cask hyprmac works as well. Or download the latest DMG from GitHub Releases and replace the app manually.

After any update method, macOS may ask you to re-grant Accessibility permission in System Settings, since the binary signature changes with each release.


Inspired By

  • Hyprland — Wayland compositor, the primary inspiration for this project
  • yabai — macOS tiling WM
  • AeroSpace — Swift macOS tiling WM with virtual workspaces
  • Amethyst — macOS tiling WM
  • skhd — Hotkey daemon

License

MIT

About

No description, website, or topics provided.

Resources

Stars

38 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages