Skip to main content

kiln.layout

A layout in kiln is a plain function: (clients, area, tag), called during a frame to declare the tiled clients of the visible tag as UI elements. t.layout holds one; assigning it changes the tag's tiling on the next frame.

local kiln = require("kiln")

-- at creation
tag.new { name = "www", screen = screen.focused, layout = kiln.layout.fair }

-- or switch a tag later, variants included
screen.focused.selected_tag.layout = kiln.layout.corner.se

The layout contract

ArgumentMeaning
clientsThe tiled clients on the tag, in list order (list order is the stack).
areaThe workarea box from the last solve, inset by the gap: { x, y, width, height }. Most layouts ignore it; carousel and magnifier use it for their arithmetic.
tagThe tag being laid out, for reading its layout parameters.

The function declares elements (usually kiln.widgets.client cells inside ui.row/ui.column containers) and returns nothing. There is no geometry API to call and no client positions to compute: a layout describes structure, and the solver produces the pixels.

How layouts tile

Built-in layouts express tiling as sizing declarations, not arithmetic. A cell is "grow" when it should take an equal share, or "N%" when a factor applies (the master's master_width_factor becomes a percent width), and the Clay solver divides the workarea among the declared cells. Splitting a region in half is just declaring two grow children; a master beside a stack is a percent cell beside a grow cell. This is why the built-in layouts are short, and why a custom layout is a page of Lua rather than a geometry engine. See Custom layouts and The Clay Bet.

The families

LayoutVariantsDescription
layout.tile.left, .top, .bottomMaster area at master_width_factor beside a stack of the rest. The suffix names where the stack goes: bare tile stacks on the right, tile.left on the left, tile.top above, tile.bottom below. master_count clients share the master; column_count splits the stack into columns.
layout.fair.horizontalBalanced grid: ceil(sqrt(n)) columns, earlier columns fill first, every cell an equal grow share. .horizontal builds rows instead.
layout.spiralEach client takes half of what remains, the split axis alternating with depth, winding inward.
layout.dwindleSame halving, always splitting toward the bottom-right.
layout.corner.nw, .ne, .sw, .seMaster fills one corner at the factor on both axes, with one stack down the far vertical edge and one across the far horizontal edge; remaining clients alternate between the two. Bare corner is .nw.
layout.magnifierUnfocused clients tile behind as a column; the focused client floats centered over them at master_width_factor of the area's size.
layout.carouselA clipped strip of fixed-width columns, scrolled so the focused client is centered. Column width is carousel_width of the workarea.
layout.maxOne client fills the workarea: the focused one if present, else the first. The others stay alive, just not declared.
layout.floatingEvery client floats at its remembered position and size; nothing tiles.

Missing pieces degrade cleanly: a tile with no stack grows the master over the whole area, a corner with one client is max.

Tag properties layouts read

Layout parameters are plain tag properties. Set them per tag; each has a default so an unconfigured tag tiles sensibly.

PropertyDefaultRead by
t.master_width_factor0.5tile, corner, magnifier (clamped to 0.05..0.95)
t.master_count1tile
t.column_count1tile
t.gaptheme.gap (8)all tiling layouts, as the space between cells
t.carousel_width0.5carousel

Module helpers

FunctionDescription
layout.name(fn)The display name of a layout function, variants included: a tag on tile.left names as "tile.left". Only the stock families have names: for a custom layout it returns nil (the stock kiln.widgets.layoutbox then shows ?).
layout.next(fn)The layout after fn in the cycle order; from a variant (or anything not in the list) it restarts the list.
layout.listThe cycle order, one entry per family. A config can replace it: kiln.layout.list = { kiln.layout.tile, kiln.layout.max }.

kiln.widgets.layoutbox and kiln.widgets.layoutlist are built on these three.

See also