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 │ 2 ││ │ ││ │ ││ │ ││ │ │├─────────────────────────────┴─────────────────────────────┤│ ││ ││ ││ 3 ││ ││ ││ ││ │└───────────────────────────────────────────────────────────┘4 windows
┌─────────────────────────────┬─────────────────────────────┐│ │ ││ │ ││ │ ││ 1 │ 2 ││ │ ││ │ ││ │ ││ │ │├─────────────────────────────┼─────────────────────────────┤│ │ ││ │ ││ │ ││ 3 │ 4 ││ │ ││ │ ││ │ ││ │ │└─────────────────────────────┴─────────────────────────────┘5 windows
┌─────────────────────────────┬─────────────────────────────┐│ │ ││ │ ││ │ ││ 1 │ 2 ││ │ ││ │ ││ │ ││ │ │├─────────────────────────────┼──────────────┬──────────────┤│ │ │ ││ │ │ ││ │ │ ││ 3 │ 4 │ 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 nmaster: 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 ││ ││ ││ ││ │└───────────────────────────────────────────────────────────┘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
State resets when calling the retile_space action or spoon.Shoji:retile().
How BSP splits work
The algorithm builds a binary tree:
- First split (depth 0): Vertical (left-right)
- Second split (depth 1): Horizontal (top-bottom)
- Third split (depth 2): Vertical again
- 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
| Aspect | BSP | Tall |
|---|---|---|
| Main window | None | Yes (left side) |
| Resize scope | Individual splits | Global ratio |
| State | Per-window ratios | Stateless |
| Best for | Many equal windows | Primary + supporting |