BSP Layout
tarmac uses a binary space partition (BSP) tree to arrange tiled windows. This is the same approach used by bspwm and yabai.
What is a BSP tree?
A BSP tree is a binary tree where:
- Internal nodes represent a split — either vertical (left/right) or horizontal (top/bottom)
- Leaf nodes represent a window
Each internal node has a split ratio (default 0.5, meaning 50/50) that determines how the available space is divided between its two children.
Split direction
When a new window is added, tarmac splits the focused leaf node into two. The split direction is chosen automatically based on the container's aspect ratio:
- Container is wider than tall → vertical split (windows side by side)
- Container is taller than wide → horizontal split (windows stacked)
This produces a natural-looking layout where narrow spaces stack vertically and wide spaces divide horizontally.
Example tree
With 4 windows (A, B, C, D), the tree might look like:
[V 0.5]
/ \
[H 0.5] [H 0.5]
/ \ / \
A B C D
This produces:
┌──────────┬──────────┐
│ A │ C │
├──────────┼──────────┤
│ B │ D │
└──────────┴──────────┘
Geometry calculation
tarmac calculates window geometry by recursively traversing the tree:
- Start with the full usable screen area (minus
gap_outerandbar_height) - At each internal node, split the area according to the split direction and ratio
- Apply
gap_innerspacing between siblings - At each leaf, the remaining area becomes the window's geometry
- Apply the geometry via the Accessibility API (set size, then position, then size again)
The size-position-size order is a workaround for macOS apps that have minimum sizes or resist resizing — the second size call ensures the window fills its designated area.
Split ratios
By default, every split is 50/50. You can adjust ratios using the resize action:
gar.bind("mod+ctrl+h", "resize left")
gar.bind("mod+ctrl+l", "resize right")
gar.bind("mod+ctrl+j", "resize down")
gar.bind("mod+ctrl+k", "resize up")
Resizing moves the nearest split divider in the specified direction, redistributing space between the two sides.
Equalize
Reset all split ratios in the current workspace to 0.5:
gar.bind("mod+e", "equalize")
Or via IPC:
tarmacctl equalize
Oversized windows
Some macOS apps have minimum window sizes that exceed the space allocated by the tree. tarmac handles this by:
- Checking the window's actual minimum size via the Accessibility API
- If the window is larger than its tile after positioning, attempting to swap with its sibling
- If swapping doesn't help, automatically floating the window
This prevents layout corruption from apps that refuse to shrink to the requested size.
Gaps
Gaps are applied during geometry calculation. gap_outer creates space at the screen edges; gap_inner creates space between adjacent windows.
gar.set("gap_inner", "8") -- 8px between windows
gar.set("gap_outer", "12") -- 12px at screen edges
Screenshot: Gap comparison
Left: no gaps. Right: inner=8, outer=12
[ placeholder — add gaps-comparison.png to public/ ]