Theming
Atelier\Diagram\Theme\Theme holds every visual decision: colors, font, spacing, stroke width. Layout engines read the theme while positioning; by the time a Scene exists, all styling is resolved into node styles. Renderers never see the theme.
Every facade exit takes an optional theme and falls back to Theme::default():
Diagram::of($model)->toSvg(); // default theme
Diagram::of($model)->toSvg($theme); // custom theme
Fields
Theme is final readonly; all fields are constructor-promoted and public.
| Field | Type | Role |
|---|---|---|
backgroundColor |
string |
diagram background |
nodeFillColor |
string |
default node fill (state boxes, badges) |
nodeStrokeColor |
string |
default node outline and edge color |
textColor |
string |
primary text |
mutedTextColor |
string |
secondary text (edge labels, legends, commit ids) |
accentColors |
list<string> |
non-empty; cycled for git branch lanes, Venn circles, and typed architecture/C4 nodes |
fontFamily |
string |
font family for all text |
fontSize |
float |
base font size, px (titles 1.15×, captions smaller) |
spacingUnit |
float |
base spacing unit, px; all layout gaps are multiples of it |
strokeWidth |
float |
base stroke width, px (default 1.5); outlines and edges derive from it |
minNodeWidth |
`float | null` |
minNodeHeight |
`float | null` |
backgroundPattern |
`Scene\BackgroundPattern | null` |
Colors are plain strings: #rrggbb or CSS named colors. The constructor throws InvalidArgumentException for an empty accentColors list or non-positive fontSize, spacingUnit, strokeWidth, minNodeWidth, or minNodeHeight.
Built-in themes
| Factory | Look |
|---|---|
Theme::default() |
light: white background, slate text, six accent colors, Helvetica at 14px, 8px spacing unit |
Theme::dark() |
deep navy background, light text, cyan outlines, six saturated accents |
Theme::blueprint() |
technical-drawing: navy field with a cyan minor grid and a heavier major grid, mono text, thin strokes |
Theme::mono() |
grayscale ink: white field, near-black outlines and text, no accent hues |
Theme::neutral() |
warm paper: soft beige field, low-contrast sand nodes, hairline strokes |
One state machine, five presets. Same model, same layout, same call: only the argument to toSvg() changed.
default()dark()blueprint()mono()neutral()These five carry their own colours, which is why they do not follow the page theme the way the other figures in this documentation do. That is the point of a preset: it decides the palette instead of inheriting one.
A custom theme
There are no setters. Construct a new Theme with named arguments:
use Atelier\Diagram\Diagram;
use Atelier\Diagram\Theme\Theme;
$dark = new Theme(
backgroundColor: '#0f172a',
nodeFillColor: '#1e293b',
nodeStrokeColor: '#94a3b8',
textColor: '#f1f5f9',
mutedTextColor: '#94a3b8',
accentColors: ['#60a5fa', '#f87171', '#4ade80', '#fbbf24'],
fontFamily: 'Helvetica, Arial, sans-serif',
fontSize: 14.0,
spacingUnit: 8.0,
);
Diagram::of($model)->saveSvg('dark.svg', $dark);
Increasing spacingUnit spreads the whole layout proportionally; increasing fontSize grows nodes with their labels. Use minNodeWidth / minNodeHeight when a style needs consistent box geometry: supported layout engines account for these dimensions before computing gaps, edge endpoints, and arrowheads.
Background pattern
A theme can carry a Scene\BackgroundPattern painted behind the nodes, on top of the solid backgroundColor. The facade transfers it onto the Scene, and the SVG renderer emits it as a concrete <pattern> (no CSS variables), so it rasterizes like any other output. It stays renderer-agnostic: a future non-SVG renderer can honor the same data.
use Atelier\Diagram\Scene\BackgroundPattern;
use Atelier\Diagram\Scene\PatternKind;
use Atelier\Diagram\Theme\Theme;
$grid = new BackgroundPattern(
PatternKind::Grid,
'#67e8f9',
size: 16.0, // minor cell, px
lineWidth: 0.45,
opacity: 0.26,
majorColor: '#e6fbff', // optional heavier layer
majorSize: 80.0, // 0 disables the major layer
);
$theme = new Theme(/* ...palette... */, backgroundPattern: $grid);
PatternKind::Dots draws one dot per cell (lineWidth is the dot radius) instead of grid lines. Theme::blueprint() ships a minor/major grid out of the box.
Low-level Scene\Style\ShapeStyle also carries renderer-agnostic stroke details such as line caps and joins. ShapeStyle::stroked() defaults to rounded caps and joins so common routes and connector paths render softly without every layout engine repeating that policy.