Skip to content

IfMax

IfMax switches between two layouts depending on how many windows are open. Use it to apply a focused layout for a few windows and a more structured one when the count grows.

At a glance

  • Switches between two layouts based on window count
  • Threshold is the max count for the below layout
  • Capabilities and state inherited from both children
  • State persists independently per child

Basic usage

local IfMax = require("layouts.combinators.if_max")
local Monocle = require("layouts.monocle")
local Tall = require("layouts.tall")
local dev = IfMax.create(2, Monocle, Tall, {
name = "dev",
displayName = "Dev",
})

With 1–2 windows the Monocle layout is used:

┌───────────────────────────────────────────────────────────┐
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ 1 or 2 │
│ (Monocle) │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
└───────────────────────────────────────────────────────────┘

With 3 or more windows, Tall takes over:

┌─────────────────────────────┬─────────────────────────────┐
│ │ │
│ │ 2 │
│ │ │
│ ├─────────────────────────────┤
│ │ │
│ │ 3 │
│ │ │
│ 1 ├─────────────────────────────┤
│ │ │
│ (Tall) │ 4 │
│ │ │
│ ├─────────────────────────────┤
│ │ │
│ │ 5 │
│ │ │
│ │ │
│ │ │
└─────────────────────────────┴─────────────────────────────┘

Threshold semantics

The threshold is the maximum window count for belowLayout:

  • #windows <= thresholdbelowLayout
  • #windows > thresholdaboveLayout

With threshold = 2: 1 or 2 windows use belowLayout; 3 or more use aboveLayout.

Error handling

IfMax.create returns nil and an error string on invalid input:

-- threshold must be a positive integer
local layout, err = IfMax.create(0, Monocle, Tall)
-- err = "threshold must be a positive integer"
-- both layouts must be valid
local layout, err = IfMax.create(2, nil, Tall)
-- err = "belowLayout is invalid"

State management

IfMax maintains state for both child layouts. Each child’s state is preserved independently, so switching back to a layout resumes exactly where it left off. State persists across layout cycles and Hammerspoon restarts.

Common mistakes

Off-by-one on threshold: IfMax.create(2, ...) means 1–2 windows use belowLayout and 3+ use aboveLayout. The threshold is the maximum count for the below layout, not the minimum for above.

Using IfMax when Partition with count would be simpler: If you want a fixed split (e.g., 1 window left, rest right), Partition with count = 1 is more direct. IfMax is for layouts that change structure entirely based on window count.

Common errors

“threshold must be a positive integer”: Passed 0 or a non-integer. The threshold must be 1 or greater.

“belowLayout is invalid” / “aboveLayout is invalid”: A child layout is missing required fields. Every layout must have at least name and arrange.