Atelier
Courses of bricks whose head joints land at an uneven offset from one course to the next

Staggered bricks

Staggered bricks draws the joints of a brick wall whose bond is dealt rather than measured: each course lands within jitter of the running bond mark instead of exactly on it. Take it for masonry, or for any coursed surface that should not look machined.

Example

<?php

declare(strict_types=1);

use Atelier\Pattern\Pattern;
use Atelier\Pattern\PatternRegistry;
use Atelier\Svg\Document;
use Atelier\Svg\Dumper\CompactXmlDumper;
use Atelier\Svg\Element\Shape\RectElement;

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

$bricks = Pattern::staggeredBricks(width: 28, height: 12, thickness: 1.2, jitter: 0.2, cells: 4, seed: 1);

$document = Document::create(360, 200);

(new PatternRegistry($bricks))->attachTo($document);

$surface = new RectElement();
$surface->setX('0')->setY('0')->setWidth('360')->setHeight('200');
$surface->setAttribute('fill', $bricks->fill());

$document->getRootElement()?->appendChild($surface);

echo (new CompactXmlDumper())->dump($document);

Options

Pattern::staggeredBricks() takes its geometry in user units, plus the height of the repeating tile and the draw. Style applies afterwards, and each call returns a new tile.

Setting Default Effect
width 28 length of one brick, and the width of the tile
height 12 height of one course
thickness 1.2 joint width, at most the brick length and at most the course height
jitter 0.2 how far a course leaves the bond mark, as a share of the brick
cells 4 courses of the repeating tile, at least 2; the period is cells * height down
seed 1 where each head joint lands inside its reach
withColor(string) currentColor paint of the joints; the bricks themselves are left transparent
withOpacity(?float) none opacity of the tile, applied to the whole drawing at once, so a head joint meeting a bed joint keeps one flat tone
withAngle(float) 0 turns the courses through patternTransform
withId(string) derived fixes the identifier instead of deriving it from the tile content

The jitter ceiling is computed from the other arguments rather than fixed: two courses each wobble by up to the jitter, so their offsets move apart by up to twice it, and past that a head joint lands on the one below, which is the straight crack a bond exists to avoid. The bound therefore depends on the bond step, the joint width, and the course count. Exceeding it throws InvalidArgumentException, and so does a course count below 2.

The same inputs and seed draw the same tiling within the same generator version. It takes part in the derived identifier, so two seeds are two definitions in the <defs> rather than one.

How the tile closes

The tile is one brick wide and cells courses tall. A course is one bed joint running the full width and one head joint standing between two bricks.

The bond has to come back where it started after those courses, or the seam between two tiles shows a straight crack down the wall. It steps by intdiv(cells, 2) / cells bricks per course, which closes for any count and is exactly half a brick, the mason's answer, whenever the count is even.

The bed joint spans the tile edge to edge and needs nothing. A head joint straddling the vertical edge is drawn a second time one period away, against the opposite edge.