How to set up PaperWM.spoon on a Mac
Install Hammerspoon, clone PaperWM.spoon into ~/.hammerspoon/Spoons, add three lines to init.lua, change two Mission Control settings and reload. It takes about ten minutes and gives you a free, niri-style scrolling strip on macOS 13 or later.
What you're installing
PaperWM.spoon is a free, MIT-licensed plugin (a "Spoon") for Hammerspoon, an app that lets Lua scripts control macOS. Inspired by PaperWM on GNOME, it gives each Mission Control Space on each screen its own horizontal strip of columns. There are no packaged releases; you install it from git. Hammerspoon itself needs macOS 13 or later.
For background on what it is and how it compares, see PaperWM for Mac. This page is just about getting it running.
Step 1: Install Hammerspoon
brew install --cask hammerspoon
You can also download it from Hammerspoon's GitHub releases. Open it once. Out of the box Hammerspoon does nothing; everything comes from your ~/.hammerspoon/init.lua.
Then give it the Accessibility permission: System Settings → Privacy & Security → Accessibility, and turn on Hammerspoon. Without this, PaperWM can't move a single window.
Step 2: Clone the Spoon
git clone https://github.com/mogenson/PaperWM.spoon ~/.hammerspoon/Spoons/PaperWM.spoon
If you already manage Spoons with SpoonInstall, the README also shows how to pull it from the project's release branch instead.
Step 3: Change two Mission Control settings
Open System Settings → Desktop & Dock and scroll down to Mission Control:
- Turn off "Automatically rearrange Spaces based on most recent use".
- Turn on "Displays have separate Spaces". macOS asks you to log out for this one to take effect.
Step 4: Add the minimal init.lua
Create or edit ~/.hammerspoon/init.lua:
PaperWM = hs.loadSpoon("PaperWM")
PaperWM:bindHotkeys(PaperWM.default_hotkeys)
PaperWM:start()
Click Hammerspoon's menu bar icon and choose Reload Config. The windows on your current Space should line up in a row. PaperWM:stop() hands the windows back if you want to turn it off from code.
Options go before PaperWM:start(). Two worth knowing: PaperWM.window_gap = 10 sets the gap in pixels, and PaperWM.window_ratios sets the widths that ⌥⌘R cycles through (golden-ratio fractions by default).
Step 5: Turn on the trackpad swipe
The swipe is off by default. Add these lines above PaperWM:start() and reload:
PaperWM.swipe_fingers = 3 -- 2, 3 or 4; 0 turns it off
PaperWM.swipe_gain = 1.0 -- higher moves further; negative reverses
If macOS also uses three fingers for "Swipe between full-screen applications" (System Settings → Trackpad → More Gestures), the two compete. Set that option to four fingers or off, or give PaperWM a different finger count.
Default hotkeys
| Keys | Action |
|---|---|
| ⌥⌘ + arrows | Focus left, right, up, down |
| ⌥⌘⇧ + arrows | Swap with the window in that direction |
| ⌥⌘C / ⌥⌘F | Centre window / full width |
| ⌥⌘R / ⌃⌥⌘R | Cycle width / cycle back |
| ⌥⌘⇧R / ⌃⌥⌘⇧R | Cycle height / cycle back |
| ⌃⌥⌘, / ⌃⌥⌘. | Anchor window left / right |
| ⌥⌘I / ⌥⌘O | Slurp into column / barf out of column |
| ⌥⌘⇧S / ⌥⌘S | Toggle stacked column / split screen |
| ⌥⌘⇧Esc / ⌥⌘⇧F | Toggle floating / raise floating windows |
| ⌥⌘1–9 | Switch to Space 1–9 |
| ⌥⌘, / ⌥⌘. / ⌃⌥⌘6 | Previous / next / most recent Space |
| ⌃⌥⌘ + arrows, ⌥⌘⇧1–9 | Move window to another Space or screen |
| ⌥⌘⇧R | Refresh windows (see the clash below) |
| ⌥⌘⇧Q / ⌥⌘⇧D | Stop PaperWM / dump state for debugging |
Known limitations
The README lists three, and they explain most surprises:
- macOS won't let a window move fully off-screen, so windows tiled off-screen sit in a visible, clickable margin at the left and right edges.
- Dragging a window to another Space or screen is hard to detect. Use the move-window shortcuts instead.
- With several screens, arrange them vertically so windows don't bleed onto the neighbouring screen. WarpMouse.spoon can make vertical screens feel side by side.
Troubleshooting
Nothing tiles
Check that Hammerspoon is on in the Accessibility list. Then choose Reload Config; Hammerspoon doesn't pick up init.lua changes until you do. If it still does nothing, open the Hammerspoon Console from the same menu and look for a Lua error.
Windows are stuck at the screen edges
That's limitation 1, not a bug. Focus them with ⌥⌘← or ⌥⌘→, or click the visible sliver. If the layout drifts, refresh the windows.
Windows show up on my other monitor
Open System Settings → Displays → Arrange and put one display above the other instead of side by side.
⌥⌘⇧R does the wrong thing
In the default table, refresh_windows and cycle_height are both bound to ⌥⌘⇧R. Move one of them before binding:
PaperWM = hs.loadSpoon("PaperWM")
local keys = PaperWM.default_hotkeys
keys.refresh_windows = { { "alt", "cmd", "shift" }, "w" }
PaperWM:bindHotkeys(keys)
PaperWM:start()
The swipe switches Spaces instead
macOS is using the same finger count. Change one of them, as in step 5.
When a native app is less work
PaperWM.spoon is a good, free tool, especially if you already use Hammerspoon and like shaping things in Lua. The trade-off is that you own the setup: config edits and reloads, the edge margins, vertical monitor arrangements, and the occasional hotkey clash. Niri vs PaperWM explains where the Spoon's model comes from.
Ribbon does the same strip as an app. Every setting is a control in a settings window, the swipe follows your fingers, columns can stack or show as tabs, and a Mac Setup page checks the macOS settings above for you. Its keys will feel familiar, just with Control + Option: ⌃⌥R cycles widths, ⌃⌥F makes a column full width. Ribbon's Mac Setup warns while Hammerspoon is running, so quit it before switching; the Ribbon setup guide covers the rest. If you'd rather stay free but drop Lua, the OmniWM alternatives page lists other options. Watch the live demo, then compare with the other options in the best scrolling window managers for Mac. Ribbon is $9.99 for one Mac; all sales are final: no refunds (see the terms).
FAQ
Is PaperWM.spoon free?
Yes. PaperWM.spoon and Hammerspoon are both free and open source under the MIT licence.
What macOS version does PaperWM.spoon need?
It doesn't state its own minimum. It runs inside Hammerspoon, which needs macOS 13 or later.
How do I turn on trackpad swiping in PaperWM.spoon?
Set PaperWM.swipe_fingers to 2, 3 or 4 before PaperWM:start() and reload the config. Make sure macOS isn't using the same finger count for switching Spaces.
Why do some windows peek in at the screen edges?
macOS doesn't let a window move fully off-screen, so PaperWM keeps off-screen windows in a thin margin at the left and right edges. The README lists this as a known limitation.
Is PaperWM.spoon the same as PaperWM on Linux?
No. PaperWM is a GNOME Shell extension for Linux. PaperWM.spoon is a separate macOS project inspired by it.