Skip to content

BSP (binary space partitioning)

Recursively splits the screen in half, creating a balanced tree of windows. Each split alternates direction: vertical, then horizontal, then vertical again. Unlike Tall and Wide, BSP has no main window. Every window can be resized individually.

Layout

1 window

┌───────────────────────────────────────────────────────────┐
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ 1 │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
└───────────────────────────────────────────────────────────┘

2 windows

┌─────────────────────────────┬─────────────────────────────┐
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ 1 │ 2 │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
└─────────────────────────────┴─────────────────────────────┘

3 windows

┌─────────────────────────────┬─────────────────────────────┐
│ │ │
│ │ │
│ │ │
│ 1 │ │
│ │ │
│ │ │
│ │ │
│ │ 3 │
├─────────────────────────────┤ │
│ │ │
│ │ │
│ │ │
│ 2 │ │
│ │ │
│ │ │
│ │ │
│ │ │
└─────────────────────────────┴─────────────────────────────┘

4 windows

┌─────────────────────────────┬─────────────────────────────┐
│ │ │
│ │ │
│ │ │
│ 1 │ 3 │
│ │ │
│ │ │
│ │ │
│ │ │
├─────────────────────────────┼─────────────────────────────┤
│ │ │
│ │ │
│ │ │
│ 2 │ 4 │
│ │ │
│ │ │
│ │ │
│ │ │
└─────────────────────────────┴─────────────────────────────┘

5 windows

┌──────────────┬──────────────┬─────────────────────────────┐
│ │ │ │
│ │ │ │
│ │ │ │
│ 1 │ 2 │ 4 │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
├──────────────┴──────────────┼─────────────────────────────┤
│ │ │
│ │ │
│ │ │
│ 3 │ 5 │
│ │ │
│ │ │
│ │ │
│ │ │
└─────────────────────────────┴─────────────────────────────┘

Each new window splits an existing space in half, alternating direction at each tree level.

Capabilities

  • Adjustable ratio: No (use per-window resize instead)
  • Adjustable main count: No (no main area concept)
  • Per-window resize: Yes
  • Stateful: Yes - remembers custom ratios

Resizing windows

BSP provides resize actions that adjust individual splits:

spoon.Shoji:bindHotkeys({
bsp_shrink_horizontal = { { "ctrl", "cmd" }, "h" },
bsp_expand_horizontal = { { "ctrl", "cmd" }, "l" },
bsp_shrink_vertical = { { "ctrl", "cmd" }, "k" },
bsp_expand_vertical = { { "ctrl", "cmd" }, "j" },
bsp_rotate = { { "ctrl", "cmd" }, "r" },
})

Expand/shrink example

Resize the split containing the focused window:

Before (window 1 focused):

┌─────────────────────────────┬─────────────────────────────┐
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ 1 │ 2 │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
└─────────────────────────────┴─────────────────────────────┘

After expand_horizontal:

┌─────────────────────────────────────────┬─────────────────┐
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ 1 │ 2 │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
└─────────────────────────────────────────┴─────────────────┘

Rotate

Flip all splits 90 degrees:

Before:

┌─────────────────────────────┬─────────────────────────────┐
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ 1 │ 2 │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
└─────────────────────────────┴─────────────────────────────┘

After:

┌───────────────────────────────────────────────────────────┐
│ │
│ │
│ │
│ 1 │
│ │
│ │
│ │
│ │
├───────────────────────────────────────────────────────────┤
│ │
│ │
│ │
│ 2 │
│ │
│ │
│ │
│ │
└───────────────────────────────────────────────────────────┘

Split-ratio model

Each split in the BSP tree has an independent ratio (default 0.5, meaning equal halves). The resize actions adjust the nearest split in the specified direction:

ActionEffect
bsp_expand_horizontalIncrease width of focused window’s vertical split by 0.05
bsp_shrink_horizontalDecrease width of focused window’s vertical split by 0.05
bsp_expand_verticalIncrease height of focused window’s horizontal split by 0.05
bsp_shrink_verticalDecrease height of focused window’s horizontal split by 0.05
bsp_rotateSwap all horizontal splits to vertical and vice versa

To reset all split ratios to 0.5, use reset_space (Ctrl+Alt+Shift+0). This clears the BSP tree state and rebuilds it from scratch.

See BSP layout actions for hotkey bindings.

State persistence

BSP remembers custom split ratios. This state persists:

  • Across retiles within the same macOS Space
  • When switching away and back to the macOS Space
  • When cycling to other layouts and returning

How BSP splits work

The algorithm builds a binary tree:

  1. First split (depth 0): Left-right (vertical divider)
  2. Second split (depth 1): Top-bottom (horizontal divider)
  3. Third split (depth 2): Left-right again
  4. And so on…

Windows distribute evenly between subtrees, creating balanced layouts regardless of window count.

When to use

BSP shines when:

  • Managing many windows (5+) that all need visibility
  • Window importance shifts during work (no fixed main window)
  • Fine-grained control over individual window sizes is needed
  • A symmetric, balanced layout is preferred

BSP vs Tall

AspectBSPTall
Main windowNoneYes (left side)
Resize scopeIndividual splitsGlobal ratio
StatePer-window ratiosStateless
Best forMany equal windowsPrimary + supporting