8. Templates
Built-in types — each a bundle over a primitive base, named because the pattern is
common. Every rectangular template is a bundle over |block|; the non-rect
primitives (SPEC 7) stand on their own. A template’s defaults are the low tier of
the cascade (SPEC 4) — every value here is overridable.
| Template | Base | Defaults | For |
|---|---|---|---|
|box| | |block| | fill: --fill; stroke: --stroke; stroke-width: 2; radius: 8; padding: 20 | The default node — a rounded, framed card. |
|rect| | |box| | radius: 0 | A sharp-cornered box. |
|group| | |block| | stroke: --group-stroke; stroke-style: dashed; stroke-width: 1; fill: --group-fill; radius: 8; padding: 20 | Dashed frame for a caption + children. |
|caption| | |block| | pin: top left; translate: 0 -20; color: --caption-color; font-size: 12∕15 of inherited ([SPEC 6](06-paint-stroke-text.md#6-paint-stroke--text)); font-weight: --caption-font-weight | A title, pinned just above the group’s top-left corner. |
|footnote| | |caption| | pin: bottom; translate: 0 19; color: --footer-color | A caption flipped to a shape’s bottom edge — a centred, muted footnote. |
|sheet-caption| | |caption| | translate: 10 10; font-size: 16∕15 of inherited; font-weight: semibold | A block title seated inside its frame’s top-left corner — what a schematic scope’s label lowers to (SPEC 16.6). |
|badge| | |block| | pin: top right; translate: 6 -6; radius: 8; padding: 2 6; shadow: 2 3 3; fill: --accent; color: --accent-text; font-size: 11; font-weight: normal | Corner pill — nudged out over the top-right corner, grows nothing. |
|row| | |block| | direction: row | Frameless wrapper — children in a row. |
|column| | |block| | direction: column | Frameless wrapper — children in a column. |
|grid| | |block| | layout: grid | Frameless grid (needs columns). |
|sign| | |icon| | width: 64; height: 64; padding: 4; stroke-width: 2; fit: contain | A larger icon as a stand-alone node, with room for a short label; fit: contain fills the box (unlike a bare |icon|). |
|table| | |group| | layout: grid; align: stretch; justify: stretch; gap: 1; gap-fill: --stroke; padding: 0; fill: none; stroke: --stroke; stroke-width: 2; stroke-style: solid; font-size: 14; font-weight: normal; scale: 1 | Ruled grid (see below). |
|cell| | |block| | padding: 4 8 | A table cell — a frameless |block| carrying the text-to-gutter inset (the mechanism: Tables, below). |
|header| | |cell| | fill: --header-fill; font-weight: semibold | A header cell — a filled, semibold band (a |table|’s first row; an |entity|’s title spans them). |
|footer| | |cell| | color: --footer-color | A footer cell — muted text; opt-in on the last row. |
|entity| | |table| | columns: auto, auto | An ER / database entity — a titled field list, rows left-aligned (see below). |
|topic| | |block| | fill: --fill; stroke: --stroke; stroke-width: 2; radius: 8; padding: 8 14 | A tree’s structural node — topic nesting is the hierarchy, anything else in its [ ] is the topic’s own content (SPEC 12); custom structural types derive from it (|person::topic|). Tree-only. |
|mindmap| | |topic| | layout: tree; direction: bilateral; routing: natural — plus the palette walk, the depth ramp, and max-width: 160 on topics (see below) | A mindmap — the node is the visible root topic, its [ ] topics the first-level branches (SPEC 12). |
|note| | |block| | fill: --fill; stroke: --stroke; padding: 20; scale: 1 | A note — the folded-corner callout card, one type in every layout (see below). |
|balloon| | |oval| | width: 16; fill: --fill; stroke: --stroke; font-size: 11; scale: 1 | An item balloon — the numbered circle an assembly leaders to a part (SPEC 15.8). |
|stack| | |block| | layout: stack; padding: 0 | The datum container (SPEC 12) — children place their origin on it instead of flowing. |
|drawing| | |block| | layout: drawing; padding: 0 | An engineering drawing — geometry on a datum, measured annotations; scale: is its drafting ratio, default 1 (SPEC 15). |
|hole| | |oval| | fill: --bg; stroke: --stroke-dark — width: required, the diameter | A round hole — punches by paint order, draws its own centre marks (SPEC 15.4). |
|centerline| | |line| | stroke-style: center; stroke: --stroke-light; stroke-width: 1; fill: none — needs points: | The dash-dot axis / symmetry line (SPEC 15.7). |
|pitch-circle| | |oval| | stroke-style: center; stroke: --stroke-light; stroke-width: 1; fill: none — width: required, the diameter | The dash-dot bolt circle; round, so a (o) reads its PCD (SPEC 15.7). |
|breakline| | |line| | stroke: --stroke-light; stroke-width: 1; fill: none — needs points: | A break cut’s edge — the thin jogged line a break: generates (SPEC 15.3); manual use is free. |
|halo| | |line| | generated chrome — halo-margin each side | An annotation line’s crossing knockout over geometry (SPEC 15.7); |halo| { … } restyles or removes them scope-wide. |
|threadline| | |line| | stroke: --stroke-light; stroke-width: 1; fill: none — generated chrome | A thread’s ISO 6410 thin line — the minor/major run and the ¾ arc a thread: generates (SPEC 15.3, SPEC 15.4). |
|hidden| | |sketch| | stroke-style: dashed; stroke: --stroke-dark; stroke-width: 1; fill: none — needs draw: | Hidden edges — interior geometry on its own dashed child, per the one-node-one-stroke-style law (SPEC 15.7). |
|shoulder| | |line| | stroke: --stroke-dark; stroke-width: 2; fill: none — needs points: | A turned part’s shoulder line — the geometry-weight edge a revolve: generates at every sharp diameter change (SPEC 15.3); manual use is free. |
|plane| | |line| | stroke-style: center; stroke: --stroke-light; stroke-width: 1; fill: none | The section-plane line on the source view — its label the section letter; at: stations it, facing: turns its arrows; a |drawing| { of: } sections it (SPEC 15.8). |
|magnifier| | |oval| | stroke: --stroke-light; stroke-width: 1; fill: none — width: required, the region diameter | The detail marker — rings a region on the source view, its label the detail letter at the rim; a |drawing| { of: } details it (SPEC 15.8). |
|projection| | |line| | stroke: --stroke-light; stroke-width: 1; fill: none — needs points: | A projection construction line — the straight thin line a sheet’s cross-view link generates (SPEC 15.8); manual use is free. |
|surface-finish| | |block| | symbol: basic; stroke: --stroke-dark; stroke-width: 1; fill: none; font-size: 12; scale: 1 | The ISO 1302 surface-texture symbol — its label the textual indication, symbol: the vee variant; drawing-scope (SPEC 15.9). |
|feature-control| | |block| | stroke: --stroke-dark; stroke-width: 1; fill: --bg; font-size: 12; scale: 1 | The GD&T frame — characteristic, tolerance, datums in ruled compartments; rows via |control|; drawing-scope (SPEC 15.9). |
|control| | |block| | — | One frame row — its label the characteristic; a |feature-control| child only (SPEC 15.9). |
|datum| | |block| | stroke: --stroke-dark; stroke-width: 1; fill: --bg; font-size: 12; scale: 1 | The framed datum letter as a node — its label the letter, an identity like >-’s; drawing-scope (SPEC 15.7, SPEC 15.9). |
|page| | |block| | layout: flow; fill: --bg — sheet: a4 unless sized; direction by orientation | An ISO 5457 drawing sheet — mm dimensions via sheet:; px per mm from the root density:; frame, zones, and centring marks as generated chrome (SPEC 15.8). |
|title-block| | |table| | font-size: 14; font-weight: semibold; stroke-width: 1 | The ISO 7200 title block — a table the |page| seats flush inside its frame’s bottom-right corner. Field properties (title, drawing-number, revision, date, sheet-number, author, …) build the standard grid, absent fields collapsing; its smart label is the title field; plain cells stay a fully custom block (SPEC 15.8). |
|frame| | |rect| | fill: none; stroke: --stroke; stroke-width: 2 | A sheet’s frame — the thick border a |page| generates at the ISO margins (SPEC 15.8). |
|field| | |block| | font-size: 12; font-weight: normal; color: --footer-color | A title-block field’s caption, over its value — quieter in size, weight, and tone (SPEC 15.8). |
|zone| | |block| | font-size: 11; color: --stroke-light | A zone reference label (1, 2… / A, B…) a |page| generates in the margin band (SPEC 15.8). |
|tick| | |line| | stroke: --stroke; stroke-width: 1; fill: none — needs points: | A zone divider / centring mark a |page| generates (SPEC 15.8). |
|schematic| | |block| | layout: schematic | A circuit sheet’s scope (SPEC 16). |
|component| | |block| | fill: --component-fill; stroke: --component-stroke; stroke-width: 1.5; radius: 0; padding: 8; prefix: "U" | The generic pin-bearing part — IC, module, relay; ref prefix U (SPEC 16.2). |
|pin| | |block| | name inside, number: outside, stub outward — no side: default (the bilateral split, SPEC 16.2) | A component terminal — the wire lands on its stub tip. |
|space| | |block| | width: 20; height: 20 — one rail slot, span: N for N | An empty slot between a component’s pins (SPEC 16.2). |
|label| | |block| | shape: plain; font-size: 11; color: --label-ink | The net tag — text, a symbol (gnd, power, …), or both; its own terminal (SPEC 16.4). |
|junction| | |oval| | fill: --wire; stroke: none — generated chrome | The connection dot where ≥ 3 wire ends meet (SPEC 16.5). |
|J| | |component| | prefix: "J" — pins nameless, pins: N generates them side: left (one column) | The connector (SPEC 16.2). |
|opamp| | |component| | prefix: "U" — pins out inp inn; power pins hidden | The amplifier triangle (SPEC 16.2). |
the discretes — |R| |C| |L| |D| |LED| |Q| |Y| |F| |FB| |SW| |BT| |V| |I| |M| |BZ| |TP| | |block| | symbol-bodied, generated pins, symbol: variants | The one/two/three-terminal parts; the type is the ref family (SPEC 16.3). |
|gnd| / |nc| | |label| | symbol: gnd / symbol: nc | Built-in ground / no-connect defines (SPEC 16.4). |
|floorplan| | |drawing| | layout: floorplan | An architectural floor plan — the drawing engine in a dialect, so |drawing|-scoped rules dress it too (SPEC 15.11). |
|wall| | |sketch| | fill: --stroke-dark; stroke: none — draw: traces the centreline; thickness: inherited (200 mm) | A wall run — offset to a solid (poché) outline at lowering; openings ride its [ ] (SPEC 15.11). |
|partition| | |wall| | thickness: 100 (mm — the true-size law, SPEC 15.11) | The thinner interior wall — a define, nothing more. |
|door| | |block| | on: required; width: 900 (mm); hinge: start; swing: left | A wall opening — gap + leaf + swing arc; symbol: single / double / sliding (SPEC 15.11). |
|window| | |block| | on: required; width: 1200 (mm) | A glazed wall opening — gap + sill lines (SPEC 15.11). |
the opening / stair chrome — |door-leaf| |door-swing| |window-sill| |stair-tread| |stair-arrow| | |line| | stroke: --stroke-light; stroke-width: 1; fill: none — generated chrome | What an opening and a flight draw: the leaf (a slider’s panels too), its quarter swing arc, a window’s sill pair, the treads and the up arrow; |door-swing| { … } restyles or removes them scope-wide (SPEC 15.11). |
the fixtures — |bed| |sofa| |dining| |bath| |appliance| |stairs| | |block| | stroke: --stroke-dark; stroke-width: 1; fill: --bg — symbol-bodied, true-size mm defaults; symbol: variants (|stairs| takes none — steps: N required) | The furniture set — thin outline, masking what it overlaps (SPEC 15.11). |
The bare |block| is the base everything rectangular builds on — frameless, yet a real
box (id, class, children, wirable, positionable): what you reach for to wrap text that
needs box behaviour.
Captions. Both caption templates are out-of-flow overlays — they never push
the content, their place fixed by the template, not by where they sit among the
children, so a row-laid group carries its title just the same. A group’s
label is its caption (SPEC 3), so |group#panel| "Settings" [ … ]
and |group#panel| [ |caption| "Settings" … ] are equal;
|caption| { font-size: 16 } styles every caption without touching body text.
Notes. A |note| is the callout card — a filled block with a folded top-right
corner. It is one type in every layout: in a sequence it binds to lifelines with
place: (SPEC 13); in a drawing it places at the
datum, usually wired by a leader (SPEC 15.7); in
flow / grid it is an ordinary padded card. Built-in scoped rules — |sequence| |note|
and |drawing| |note|, each { padding: 6 10; font-size: 13 } — keep it compact where
convention expects; override them like any rule.
Topics & mindmaps. A |topic| is the tree’s structural node
(SPEC 12), a compact card whose label is its centred
text. |mindmap| is the visible root topic owning the scene — layout: tree; direction: bilateral; routing: natural — plus three deterministic garnishes,
each lowered at desugar as ordinary generated rules (visible in lini desugar, overridable like any rule): the palette walk — each first-level
branch takes the next hue (SPEC 10.2) in
declaration order, red and grey skipped, and tints its subtree at the tiers
(wash fill, deep stroke and branch wires, ink text; the root stays
neutral, explicit paint wins, cross-links stay neutral, dark mode free); the
depth ramp — .lini-level-N rules size the tiers (root largest, level 1
medium, deeper small); and topic wrap — max-width: 160, so a long label
wraps into a card instead of stretching an arm. A plain layout: tree
carries none of these — org charts read monochrome.
Tables. A |table| is pure sugar over the bundle above — its 1px
gap-fill gutters paint as hairline rules (SPEC 11).
Each body cell wraps in a |cell|; |header| / |footer| build on it, so
every cell — but not the caption, a plain |block| — carries the inset. Style
all cells with |cell| { … }, or per table with |table| |cell| { … }. The
table’s align: stretch; justify: stretch makes every cell fill its track
— backgrounds fill and text has room. A table’s label is its caption.
Column alignment. align (↔) / justify (↕) on the table read per column
(SPEC 12) and align the cells’ text: since the cells already fill, the
table’s own align/justify are carried onto each cell — a start/end column’s cells
wear a .lini-align-* / .lini-justify-* class — and a filled cell places its text at
that edge (center is the default). So align: start, center, end reads three columns
left / centre / right, header band and body alike.
A table’s first row becomes its header — each cell wrapped as a |header|, a filled
semibold band; |table| |header| { font-weight: normal; fill: none } reverts it. A footer
is opt-in: wrap a last-row cell in |footer|. Every cell is a box now — header/footer
carry a fill; a body cell is a frameless |block| wrapping its text, so the padding rule
and the column’s alignment reach it (SPEC 18).
|table#basket| {
columns: 80, 140, 80;
} [
"Fruit" "Quantity" "Notes" // the header row — filled + bold
"Apple" "12" "fresh"
"Mango" "3" "ripe"
]
fmt knows the column count and pads the cells into aligned columns, so the flat form
reads like the table it is. A cell that must be placed or linked is a box child
(|cell| "X" for a padded cell, or |box| { cell: 2 1; … }); a cell that just needs a
colour or weight can take its own style block ("Apple" { color: --red-ink }).
Entities. An |entity| is sugar over |table| (two auto columns) for an ER /
database card: its label is its title — a |header| spanning every column, centred
over left-aligned "field" "type" rows (an entity’s field rows read left by default; the
title keeps its centred, full-span band). Add a column for a key gutter —
{ columns: auto, auto, auto } gives "PK"/"FK" "field" "type". In an entity (not a plain
table) a |header| / |footer| cell spans the full width.
|entity#users| "Users" [ "id" "int" "name" "varchar" ]
Relationships are ordinary links with the ER cardinality operators (SPEC 9):
users -< orders is one-to-many, a >-< b many-to-many, landing on the entity
edge. To anchor a wire to one field, give that cell an id
(|cell#user_id| "user_id") and link the path (orders.user_id -< users.id):
the card’s cells tile, so the wire leaves the card at that field’s row
rather than crossing the cells (ROUTING).
Keys are plain content ("id" { font-weight: bold }); an entity adds no grammar.
Extend any template: |panel::group| { stroke: --accent }. Common nodes need no
template:
| For | Write |
|---|---|
| Circle | |oval| { width: 40 } |
| Database | |cyl| |
| Arrow | |line| { marker-end: arrow; points: 0 0, 50 0 } |