atelier / layout
Renderer-agnostic spatial composition primitives: geometry, box constraints, grids, text layout, and links between boxes
Fund package maintenance!
Requires
- php: >=8.3
- ext-mbstring: *
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.94
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^12.5
This package is auto-updated.
Last update: 2026-08-13 04:11:46 UTC
README
Spatial primitives that answer where things go, and return geometry rather than markup.
Describe boxes, tracks, text, padding and constraints; get back frames any renderer can consume. Nothing here emits SVG, HTML, or a DOM, and nothing here names a consumer.
$result = Grid::tracks('row', [TrackSize::fixed(48), TrackSize::fr(), TrackSize::fixed(48)]) ->gap(8) ->add(Frame::fixed('left', 32, 32)) ->add(Frame::stretch('middle')) ->add(Frame::fixed('right', 32, 32)) ->solve(new LayoutContext(), Rect::fromSize(240, 48)); $result->frameOf('middle'); // Rect(56, 0, 128, 48)
Separating the geometry from the drawing is what lets the same solver serve a chart legend, a
diagram node, and a page header. It is the layer atelier/diagram sits on. Backed by an
extensive test suite and PHPStan at its highest level.
Composition · Geometry · Text · Links between boxes · Charts and boards · Documentation
Installation
composer require atelier/layout
Requires PHP 8.3 or later. No dependencies.
Quick start
use Atelier\Layout\Alignment; use Atelier\Layout\Element\TextBlock; use Atelier\Layout\Geometry\Rect; use Atelier\Layout\LayoutContext; $text = TextBlock::of('caption', 'A label that wraps', 12) ->align(Alignment::Center, Alignment::End) ->layout(new LayoutContext(), new Rect(0, 0, 90, 48)); $text->lines; // one frame and one baseline per line $text->hasOverflow(); // reported, never hidden
See Getting started.
Composition
Six primitives, each answering one question about where a child ends up: stacks along one axis, grids on two, alignment inside a box, distribution of what is left over, groups that carry a bounding box, and overlays anchored to a corner.
Track sizes are fixed, content-sized, or flexible, and a grid auto-flows past its column count. See Stacks and Grid.
Geometry
Immutable values with no behaviour beyond their own maths: Rect, Point, Size, Insets,
Bounds, Circle, BoxModel, and a RectIndex for collision and occupancy queries.
Box constraints travel down a node tree during measurement and sizes travel back up, which is what makes a layout solvable in one pass. See Geometry.
Text
Measurement, wrapping, per-line frames, baselines, and overflow, because all five change geometry and none of them are the renderer's business.
The default measurer is deterministic and approximate on purpose: server-side rendering and
tests both need stable numbers, and a font engine gives neither. A more precise one is injected
through LayoutContext. See Text.
Links between boxes
Where a connection leaves one rectangle, where it enters another, and the right-angle path in between, as points rather than path data.
use Atelier\Layout\Connection\OrthogonalConnector; $connection = (new OrthogonalConnector())->connect($from, $to); $connection->points; // 100,40 -> 140,40 -> 140,80 -> 180,80 $connection->labelPoint; // where an edge label belongs $connection->tipTangent; // the final direction, for an arrowhead
Label placement avoids solved rectangles deterministically. Graph ranking, obstacle avoidance and edge bundling are deliberately not here. See Links between boxes.
Charts and boards
The recurring furniture: parallel lanes with a reserved header, an edge strip for an axis, and a key made of swatches and labels. Each takes a rectangle and returns placed frames.
See Tracks, bands and legends.
Documentation
- Getting started: solve a grid, some text, and a link.
- Composition: stacks, grid, alignment, distribution, groups, overlays.
- Geometry: the value types, constraints, and fitting.
- Text: measuring, wrapping, baselines, overflow.
- Links between boxes: ports, connectors, labels.
- Tracks, bands and legends: lanes, axis strips, keys.
The full documentation is published at ateliersvg.com/layout.
Contributing
Contributions are welcome. Visit the project on GitHub to report a bug, suggest a feature, or open a pull request.
Before submitting code, run:
composer qa # PHP-CS-Fixer, PHPStan at level max, and PHPUnit
A new public primitive needs exact numeric tests before a consumer depends on it.
Support
Bug reports, security disclosures, and contribution guidelines are collected at ateliersvg.com/support.
Atelier is maintained by Simon André. Sharing the package or starring it on GitHub helps more than you would think.
License
Atelier Layout is released under the MIT License.