How to set up PaperWM.spoon on a Mac

Updated 2026-10-22 · by the maker of Ribbon

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:

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

KeysAction
⌥⌘ + arrowsFocus left, right, up, down
⌥⌘⇧ + arrowsSwap with the window in that direction
⌥⌘C / ⌥⌘FCentre window / full width
⌥⌘R / ⌃⌥⌘RCycle width / cycle back
⌥⌘⇧R / ⌃⌥⌘⇧RCycle height / cycle back
⌃⌥⌘, / ⌃⌥⌘.Anchor window left / right
⌥⌘I / ⌥⌘OSlurp into column / barf out of column
⌥⌘⇧S / ⌥⌘SToggle stacked column / split screen
⌥⌘⇧Esc / ⌥⌘⇧FToggle floating / raise floating windows
⌥⌘1–9Switch to Space 1–9
⌥⌘, / ⌥⌘. / ⌃⌥⌘6Previous / next / most recent Space
⌃⌥⌘ + arrows, ⌥⌘⇧1–9Move window to another Space or screen
⌥⌘⇧RRefresh windows (see the clash below)
⌥⌘⇧Q / ⌥⌘⇧DStop PaperWM / dump state for debugging

Known limitations

The README lists three, and they explain most surprises:

  1. 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.
  2. Dragging a window to another Space or screen is hard to detect. Use the move-window shortcuts instead.
  3. 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.

Keep reading