← All libraries

CandyLayout

🍬 CandyLayout

Constraint-based layout solver for terminal grids

inspired by ratatui/ratatui layout constraint-solver foundation-package

Two solvers behind a LayoutSolver interface: CassowarySolver (simplex-based, optimal, handles stay/edit constraints) and GreedySolver (deterministic 5-phase fallback ported from candy-sprinkles). Swap solvers without touching call-sites. Foundation for candy-sprinkles, sugar-bits, and candy-forms layout.

Install

composer require sugarcraft/candy-layout

Quickstart

use SugarCraft\Layout\{Constraint, Direction, GreedySolver, Region};

$solver = GreedySolver::new();
$region = Region::fromSize(100, 24);

$rects = $solver->solve($region, Direction::Horizontal, [
    Constraint::length(20),      // exactly 20 cells
    Constraint::min(10),          // at least 10, takes more if available
    Constraint::fill(1),         // fills remaining space (weight 1)
    Constraint::percentage(30),     // 30% of total
    Constraint::ratio(1, 3),     // 1/3 of remaining after fixed
    Constraint::max(50),          // ceiling — greedy but clamped
]);

Solvers

GreedySolverDeterministic 5-phase fallback. Bit-identical output to the existing candy-sprinkles Solver. No deps, no edit variables. Fast and predictable.
CassowarySolverFull simplex with Big-M method. Handles stay constraints and edit variables. Simplification of Badros & Borning 2001 for 1D integer outputs.

Constraint types

LengthFixed cell count — takes exactly n cells.
MinFloor — at least n cells, grows if slack available.
MaxCeiling — greedy, clamped to n cells.
FillProportional remainder — weight controls distribution across multiple Fill constraints.
PercentageFraction of total — n% of the available dimension.
RatioFractional proportion — num/denom of remaining space after fixed constraints.

Use it for

Source & demos

Try the quickstart →

API

ClassMethodDescription
LayoutSolversolve(Region, Direction, list<Constraint>)Solve constraints against a region in the given direction; returns list of sub-regions
LayoutSolvergreedy(): selfFactory: create a GreedySolver
LayoutSolvercassowary(): selfFactory: create a CassowarySolver
GreedySolvernew(): selfDefault factory
CassowarySolvernew(): selfDefault factory
DirectionHorizontal, VerticalEnum: split direction
RegionfromSize(int, int)Factory: width, height
Constraintlength(int)Fixed cell count
Constraintmin(int)Floor — at least n cells
Constraintmax(int)Ceiling — at most n cells
Constraintfill(int $weight)Proportional remainder with weight
Constraintpercentage(int 0-100)Percentage of total
Constraintratio(int $num, int $denom)Fractional proportion