Atelier

Getting started

Install

composer require atelier/field

Requires PHP 8.3 or later and atelier/svg. Randomness comes from ext-random, bundled with PHP since 8.2, so nothing else has to be installed for a seeded field to draw the same thing twice.

Cover an area

A factory takes the area first, then its own geometry, then a seed. What comes back is a value: it needs no document to exist, and building one mutates nothing.

<?php

declare(strict_types=1);

use Atelier\Field\Field;

require __DIR__.'/vendor/autoload.php';

echo Field::waves(1200, 400, layers: 6, seed: 7)->toSvg();

toSvg() returns a standalone document at the size the field was given. It knows that size, so unlike a tile it needs no dimensions passed back to it.

Put it in a document you already hold

use Atelier\Svg\Document;

$document = Document::create(1200, 400);

$document->getRootElement()?->appendChild(
    Field::waves(1200, 400, layers: 6, seed: 7)->element()
);

element() returns one <g> holding the whole drawing, ground included when the theme paints one. Nothing is registered in <defs>: a field is content, not a paint server.

Take it as a CSS background

echo Field::waves(1600, 500)->withColor('#0067a0')->toCss();
background-image: url("data:image/svg+xml,...");
background-repeat: no-repeat;
background-size: cover;

A background image is a document of its own, so currentColor resolves to black there. Set a real colour before calling toDataUri() or toCss().

Colour it

use Atelier\Field\Theme;

Field::waves(1200, 400)
    ->withTheme(Theme::blueprint()->with(palette: []))
    ->withColor('#0067a0')
    ->withBackground('#f6f5f1')
    ->withOpacity(0.6);

Each call returns a new field. The default foreground is currentColor and no ground is painted, so inline SVG inherits the colour of its ancestors.

A nonempty palette takes precedence over the foreground for toned fills. withColor() changes only the foreground; it does not replace palette entries. The example clears the palette to use one ink. With a palette, colours cycle when there are more layers than entries. Without a palette, the layers are told apart by depth alone. The palette is a ramp read back to front, not a set of series colours: a categorical palette on a stack of layers reads as stripes rather than as distance.

The same seed draws the same field

Field::waves(1200, 400, seed: 7)->toSvg() === Field::waves(1200, 400, seed: 7)->toSvg();

Randomness is Random\Randomizer over Random\Engine\Xoshiro256StarStar, both from the PHP core. Identical inputs reproduce the same drawing with the same generator implementation and supported runtime behavior. Fixed output fixtures detect changes during development; they do not promise byte stability across package or dependency releases. Keep an exported SVG when you need a permanent asset.

Input limits

Width and height must be finite and greater than zero. Each generator also validates its own counts and proportions; see its options table for the exact interval. Some controls accept zero, including opacity, Terrain relief and Voronoi stroke thickness. NAN and INF are rejected.

Each invalid call below is caught separately, so both examples execute:

foreach ([['width' => 0, 'height' => 400], ['width' => 1200, 'height' => 400, 'layers' => 0]] as $arguments) {
    try {
        Field::waves(...$arguments);
    } catch (\Atelier\Field\Exception\InvalidArgumentException $error) {
        echo $error->getMessage(), PHP_EOL;
    }
}

Viewport, coverage and resizing

Width and height define the drawing's coordinate frame, not a promise to paint every pixel. Blob, Halftone, Foam and Archipelago deliberately leave transparent regions. withBackground() paints the whole frame. Geometry clipping limits path coordinates; a stroke can extend half its width beyond its centreline. An appended group does not clip its own stroke bounds.

Standalone exports include a matching viewBox. Resizing that SVG scales its existing geometry, including cell sizes and strokes. Regenerating with different dimensions recalculates the layout and may change sample counts and shape positions. For an appended group, set the enclosing SVG's viewBox or apply a transform yourself.

Precision and cost

Coordinates serialize to four decimal places. Work in ordinary display-sized user units, such as a frame hundreds or thousands of units wide, and scale the SVG when a different display size is needed. Features below 0.00005 units can round to zero. Very large values can overflow intermediate calculations even when the inputs are finite; guards do not establish useful output at every accepted scale.

Cost depends on the generator. Fixed layer or ray counts differ from lattices whose sample count grows with width and height divided by cell size. Avoid extreme area-to-cell ratios; the package does not impose a common time, memory or output-size bound.