Skip to content
anthonyradkePublic

About

A scrolling, tiling window manager for macOS

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

17 Commits

Folders and files

Repository files navigation

Reel icon

Reel

A scrolling, tiling window manager for macOS.

macOS 13 or later Swift 5.10

Reel arranges windows as columns on a horizontal strip, one strip per display and Space, in the style of niri and PaperWM. A new window opens as a column next to the focused one without resizing the others. When the strip is wider than the screen, it scrolls with the keyboard or a three or four finger trackpad swipe.

It's a native AppKit app with no scripting layer to set up and no dependencies outside the system frameworks.

Moving focus along the strip with the keyboard

Features

  • Normal windows tile into columns. Dialogs, sheets, Quick Look, fixed-size windows and anything matched by a rule stay floating.
  • Columns have preset widths (a third, a half and two thirds by default) that you cycle through, plus full width and free resizing with the keyboard or by dragging a window edge.
  • Several windows can share a column, either stacked with adjustable heights or shown as tabs.
  • A column can be pinned to the left or right edge so it stays put while the rest of the strip scrolls.
  • Scrolling uses a spring animation, and the strip follows a trackpad swipe one to one with momentum.
  • Each display has its own strip. Windows that reach the edge of a neighbouring display are hidden instead of spilling onto it.
  • Native macOS tabs, minimised windows, hidden apps and full-screen windows return to their place on the strip.
  • The layout survives a restart of Reel, sleep and display changes.
  • Optional focus border, dimming of unfocused windows, and a strip overview at the top of the screen that can be clicked or dragged to reorder columns.
  • Every shortcut can be rebound. Settings are a plain JSON file that reloads on save.

A new window opening beside the focused one Cycling preset widths and full width

Scrolling the strip with a trackpad swipe Stacking windows in a column and showing them as tabs

Requirements

  • macOS 13 Ventura or later, on Apple silicon or Intel.
  • The Accessibility permission, which macOS requires for an app to move other apps' windows.

Install

Prebuilt releases aren't published yet. Build and install from source (Xcode 15.3 or later):

git clone https://github.com/anthonyradke/reel.git && cd reel
./scripts/build-app.sh --install

The first launch walks through granting the Accessibility permission. The Mac Setup page in the settings checks the trackpad and Spaces options that Reel works best with, and warns if another window manager is running.

Keyboard shortcuts

All defaults use ⌃⌥ (Control-Option). Holding ⌃⌥ for a moment shows the strip overview. Every shortcut can be changed, or given a second key, on the Shortcuts page.

Keys Action
⌃⌥ ← → or H L Focus the column to the left or right
⌃⌥ ↑ ↓ or K J Focus the window above or below in a stacked column
⌃⌥⇧ with any of the above Move the window instead of the focus
⌃⌥⌘ ← → Focus the first or last column (⌃⌥⌘⇧ moves the column there)
⌃⌥ 1 to 9 Focus a column by position, 9 always being the last (⌃⌥⇧ moves the column there)
⌃⌥ R Cycle preset widths (⇧ cycles backwards)
⌃⌥ F Toggle full width
⌃⌥ C Centre the column
⌃⌥ = and - Wider and narrower (⇧ for taller and shorter in a stack)
⌃⌥ 0 Equal heights in a stack
⌃⌥ [ and ] Stack the window into the column on the left or right
⌃⌥⇧ [ and ] Take the window out of its stack, to the left or right
⌃⌥⇧ T Toggle tabs for the column
⌃⌥ T Float or tile the window
⌃⌥ P Pin the column to the left edge (⇧ for the right)
⌃⌥ N Send the window to the next display
⌃⌥ , Open settings
⌃⌥ Q Stop Reel and bring every window back on screen

A column holds one window until another is stacked into it with ⌃⌥ [ or ]. The stack splits the column's height, or shows one window at a time under a tab bar after ⌃⌥⇧ T. Dragging a window onto another column, or out of one, does the same as the keys.

Configuration

Reel's layout settings

Everything is set from the settings window (⌃⌥ ,). The same settings live in a JSON file that can be edited by hand and is reloaded as soon as it's saved.

File Contents
~/Library/Application Support/Reel/config.json Settings, shortcuts and window rules
~/Library/Application Support/Reel/session.json The saved strips, restored on launch
~/Library/Logs/Reel/engine.log Engine log

Scripting

Every action has a name and can be triggered from outside the app in three ways:

open -g reel://focus-right    # URL scheme
reelctl move-to-3             # command line client
reelctl status                # strips and windows as JSON
reelctl set gap 12            # change a setting

The Automation page in the settings links reelctl into ~/.local/bin and can export Raycast script commands. reelctl --help lists the actions.

How it works

Module Role
ReelCore The strip model, layout maths, commands, config and the spring. Pure Swift with no AppKit, and covered by the unit tests.
Reel The app: Accessibility and SkyLight calls, window tracking, the display-synced animator, hot keys, trackpad gestures, overlays and the SwiftUI settings.
reelctl A small client that talks to the running app over a Unix socket.

Window moves are sent from one background queue per app, so a slow or hung app only delays its own windows, and intermediate animation frames are dropped rather than queued when an app can't keep up. Every Accessibility call has a short timeout for the same reason.

Build from source

Requires Xcode 15.3 or later (Swift 5.10).

swift test                      # unit tests for ReelCore
./scripts/build-app.sh          # build/Reel.app
./scripts/build-app.sh --dmg    # also build/Reel.dmg
./scripts/build-app.sh --install

The build script signs with the first Apple Development or Developer ID identity in the keychain, or ad hoc if there isn't one. Signing with the same identity each time keeps the Accessibility permission across rebuilds.

docs/development.md covers the live test that drives real windows and the tooling that generates the demos and screenshots.

Known limitations

  • macOS doesn't let a window sit entirely off screen, so columns scrolled out of view are parked at the edge of the display (one point stays on screen) rather than truly hidden.
  • Windows are moved through the Accessibility API, so an app that enforces a minimum size or ignores a resize keeps its own size, and a slow app animates less smoothly than the rest of the strip.
  • Spaces are read through the private SkyLight framework (read-only). A future macOS release could change it.
  • It can't run alongside another tiling window manager; both would fight over the same windows.
  • Builds are signed with a local development identity or ad hoc, not notarized.

License

MIT. See LICENSE.

About

A scrolling, tiling window manager for macOS

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages