6. Layer 3 — Notation (visual definition)
Contents of DISL 0.1
The notation layer defines the concrete syntax: how every node, edge, port and label looks, from a plain rectangle to a finely parameterised shape with draggable handles and embedded form widgets, and from a straight line to a rounded orthogonal route with a double casing, custom arrowheads and labels at its start, middle and end.
{
"notation": {
"theme": { "tokens": {}, "modes": { "dark": {} } },
"styles": { "base": {}, "state": { "extends": "base" } },
"shapes": { "folder": {} },
"markers": { "openDiamond": {} },
"icons": { "bolt": { "svg": "…" } },
"nodes": { "State": {} },
"edges": { "Transition": {} },
"ports": { "Block.in": {} },
"canvas": {},
"doc": "…"
}
}
Resolution of a visual property. For a given element, the value of a visual property (for example stroke.width of a node's body) is resolved in this order; the first value found wins:
- Per-element style override stored in the DID definition's view data (11.6), if the specification allows overrides.
- Interaction state styles (
states.selected,states.hover, …) that are active, in the fixed prioritydragging>selected>focused>hover>highlighted>dropTarget>invalid>warning>disabled. - Conditional styles (
conditions) whosewhenexpression is true, in declaration order (later wins). - Variants (
variants) whosewhenis true — they may replace shape, size, labels and style. - The notation's own
style(inline or referenced), withextendschains resolved. - The notation of the nearest supertype (C3 order), repeating steps 2–5.
- The viewpoint override and then the global
notation.defaultsfor the element kind. - The built-in default (Appendix B.1).
Properties merge per key: a state style that only sets stroke.color keeps the resolved stroke.width.
Tokens give colors, fonts and sizes semantic names so that one specification renders correctly in light mode, dark mode, high contrast and the brand palette of an organisation.
{
"theme": {
"tokens": {
"color.surface": "#FFFFFF",
"color.text": "#1F1E1C",
"color.border": "#8A8880",
"color.accent": "#534AB7",
"color.accent.soft": "#EEEDFE",
"color.danger": "#E24B4A",
"font.body": "Inter, system-ui, sans-serif",
"font.mono": "JetBrains Mono, monospace",
"size.corner": 8,
"size.stroke": 1.25
},
"modes": {
"dark": {
"color.surface": "#1F1E1C",
"color.text": "#F1EFE8",
"color.border": "#B4B2A9",
"color.accent.soft": "#3C3489"
},
"high-contrast": { "color.border": "#000000", "size.stroke": 2 }
},
"defaultMode": "light",
"followSystem": true
}
}
| Property | Type | Description |
|---|---|---|
tokens |
map qualified id → value | Base token values (colors, font stacks, numbers, strings). |
modes |
map mode → token map | Overrides per mode. Mode names are free; light, dark and high-contrast are recognised by runtimes. |
defaultMode |
string | Initial mode. |
followSystem |
bool | Follow the operating system's light/dark preference. |
extends |
string | Name of an imported theme to extend ("corp.theme"). |
Tokens are referenced with { "token": "color.accent" } in any Bindable position, and from CEL with token('color.accent'). Runtimes MAY let users switch modes; DID definitions never store resolved token values unless a user explicitly overrides a style.
A Paint fills an area or colors a stroke.
| Form | Example |
|---|---|
| Color | "#EEEDFE", "transparent", "currentColor" |
| Token / CEL / attribute | { "token": "color.accent" }, { "cel": "self.done ? '#639922' : '#BA7517'" }, { "attribute": "color" } |
none |
"none" — no paint (unlike transparent, none is not hit-testable). |
| Linear gradient | { "type": "linear", "angle": 90, "stops": [ { "offset": 0, "color": "#FAC775" }, { "offset": 1, "color": "#EF9F27" } ] } |
| Radial gradient | { "type": "radial", "center": [0.5, 0.5], "radius": 0.7, "stops": [ … ] } |
| Pattern | { "type": "pattern", "pattern": "hatch", "color": "#888780", "background": "#FFFFFF", "spacing": 6, "angle": 45, "width": 1 } |
| Image | { "type": "image", "src": "icons/brick.png", "fit": "tile", "opacity": 0.5 } |
Built-in patterns: hatch, cross-hatch, dots, grid, vertical, horizontal, zigzag, checker, bricks. Patterns are also RECOMMENDED as a secondary visual cue when color distinguishes categories, for accessibility (6.15).
Gradient stops accept Bindable colors, so gradients can follow tokens. offset is a fraction.
A Stroke describes how an outline or a line is drawn. The same object is used for node outlines, edge lines, separators, grid lines and marker outlines.
| Property | Type | Description |
|---|---|---|
color |
Paint | Default { "token": "color.border" } or #5F5E5A. |
width |
Bindable number | Canvas units. Default 1. |
minWidthScreenPx |
number | Lines never render thinner than this on screen when zoomed out (hairline preservation). |
opacity |
fraction | Default 1. |
dash |
DashStyle | See below. Default "solid". |
dashOffset |
number | Phase of the dash pattern. |
dashScale |
"absolute", "width" |
Whether dash lengths are canvas units or multiples of width. Default "width". |
cap |
"butt", "round", "square" |
Line cap. Default "butt". |
join |
"miter", "round", "bevel" |
Line join. Default "miter". |
miterLimit |
number | Default 4. |
align |
"center", "inside", "outside" |
Stroke alignment on closed outlines. Default "center". |
double |
{ "gap": 2, "innerColor": Paint } |
Draw two parallel lines (UML composition borders, "is-a" rails, road casings). |
casing |
{ "color": Paint, "width": 4 } |
Draw a wider line underneath (halo). Makes edges readable where they cross others. |
effect |
LineEffect | Geometric effect along the path (below). |
flow |
{ "speed": 20, "direction": "forward" } |
Animated dash movement along the path (data flow, active connections). Runtimes MUST honour reduced-motion preferences and MAY disable it. |
sketch |
{ "roughness": 1.2, "bowing": 1, "seed": {cel} } |
Hand-drawn rendering. The seed SHOULD be derived from the element id so the sketch is stable. |
DashStyle is one of the named presets or an explicit array of alternating dash and gap lengths:
| Preset | Pattern (in multiples of width) | Typical use |
|---|---|---|
solid |
– | Default |
dashed |
[4, 3] |
Optional, dependency, inheritance of interfaces |
long-dash |
[8, 4] |
Boundaries, planned items |
short-dash |
[2, 2] |
|
dotted |
[0.1, 2] with round cap |
Annotations, notes, traces |
dash-dot |
[6, 3, 0.1, 3] with round cap |
Center lines, axes |
dash-dot-dot |
[6, 3, 0.1, 3, 0.1, 3] |
Phantom lines |
[n, …] |
explicit | Anything else |
LineEffect modifies the geometry of a line or outline:
type |
Parameters | Result |
|---|---|---|
wave |
amplitude, wavelength |
Sine wave along the path (signals, "wireless", uncertain dependencies). |
zigzag |
amplitude, wavelength |
Zigzag (lightning, "breaks" on axes). |
loops |
radius, spacing |
Coil (springs, inductors). |
ticks |
length, spacing, side ("left", "right", "both") |
Tick marks along the line (railways, fences, boundaries). |
arrows |
spacing, marker |
Repeated small arrowheads along the line (flow direction on long edges). |
offset |
distance |
Parallel offset (lane markings). |
plugin |
name, args |
Custom effect. |
Effects apply to the path before dashes, so a dashed wave is possible. Effects never change the hit-test geometry, which follows the base path widened by hitWidth (6.10).
A Font object:
| Property | Type | Description |
|---|---|---|
family |
Bindable string | Font stack. Default { "token": "font.body" } or "system-ui, sans-serif". |
size |
Bindable number | Canvas units. Default 14. |
minSizeScreenPx |
number | Text below this on-screen size is hidden or replaced by a placeholder bar (level of detail). |
weight |
100–900 or "normal", "bold" |
Default 400. |
style |
"normal", "italic" |
|
color |
Paint | Default { "token": "color.text" }. |
lineHeight |
number | Multiple of size. Default 1.3. |
letterSpacing |
number | Canvas units. |
decoration |
"none", "underline", "line-through", "overline" |
UML static members are underlined, for instance. |
transform |
"none", "uppercase", "lowercase", "capitalize" |
|
variant |
"normal", "small-caps", "tabular-nums" |
|
halo |
{ "color": Paint, "width": 3 } |
Outline around glyphs for legibility over lines and fills. |
Font files MAY be declared in notation.fonts: { "Inter": { "src": ["fonts/Inter.woff2"], "weights": [400, 600] } }. Runtimes that cannot load a font use the next family in the stack.
A Style bundles visual properties. Styles are declared in notation.styles and referenced by name, or written inline.
| Property | Type | Description |
|---|---|---|
extends |
style name or name[] | Inherit from other styles (merged left to right, then own properties). |
fill |
Paint | Area fill. |
fillOpacity |
fraction | |
stroke |
Stroke | Outline or line. |
opacity |
fraction | Whole-element opacity. |
cornerRadius |
number or [tl, tr, br, bl] |
For shapes that support it. |
shadow |
{dx, dy, blur, color} or "none" |
Drop shadow. Runtimes MAY omit shadows in low-power modes. |
font |
Font | Default font for labels of the element. |
textAlign |
"left", "center", "right", "justify" |
|
verticalAlign |
"top", "middle", "bottom" |
|
padding |
Insets | Inner spacing for labels and content. |
cursor |
CSS cursor name | Pointer cursor over the element. |
filter |
"none", "grayscale", "blur" |
Visual filter (for disabled or ghost elements). |
blend |
CSS blend mode | |
visible |
Bindable bool |
{
"styles": {
"base": { "fill": { "token": "color.surface" },
"stroke": { "color": { "token": "color.border" }, "width": { "token": "size.stroke" } },
"font": { "size": 13 } },
"emphasis": { "extends": "base", "stroke": { "width": 2 }, "font": { "weight": 600 } },
"ghost": { "extends": "base", "opacity": 0.5, "stroke": { "dash": "dashed" } }
}
}
Interaction states. Every node, edge, port and label notation MAY declare states, a map from state to Style:
| State | Active when |
|---|---|
hover |
Pointer is over the element. |
selected |
Element is in the selection. |
focused |
Element has keyboard focus. |
dragging |
Element is being moved or resized. |
highlighted |
Highlighted by search, a problem link, a hook action or a related selection. |
dropTarget |
A dragged element can be dropped into this container or connected to this element. |
dropReject |
A dragged element cannot be dropped or connected here (a connect/containment constraint failed). |
invalid |
The element has at least one problem with severity error. |
warning |
The element has at least one problem with severity warning (and none with error). |
disabled |
The element is read-only (locked, or enabled of its notation is false). |
editing |
A label of the element is being edited inline. |
Runtimes provide sensible defaults for hover, selected, dropTarget, dropReject, invalid and warning (for example a selection outline and a red problem badge) that apply when the specification declares none.
Conditional styles apply when an expression holds:
{
"conditions": [
{ "when": "self.priority == 'high'", "style": { "stroke": { "color": { "token": "color.danger" }, "width": 2 } },
"doc": "High-priority tasks have a red border." },
{ "when": "self.done", "style": "ghost" }
]
}
A node's body is a shape. A shape reference is either a name ("ellipse"), or an object with a type and parameters, where every parameter is Bindable:
{
"shape": "roundedRect",
"shape": { "type": "roundedRect", "params": { "radius": 12 } },
"shape": { "type": "polygon", "params": { "sides": { "cel": "self.corners" }, "rotation": 0 } },
"shape": { "type": "note", "params": { "fold": 14 }, "doc": "Folded corner signals a comment." }
}
The standard library offers these primitives (all parameters optional; defaults in Appendix B.2):
| Shape | Parameters | Notes |
|---|---|---|
rect |
– | |
roundedRect |
radius, radii [tl,tr,br,bl] |
|
pill |
– | Stadium; radius = half the smaller side. |
ellipse |
– | Circle when width = height. |
circle |
– | Always circular; size is min(width, height). |
diamond |
– | Rhombus touching the bounds' midpoints. |
triangle |
apex (fraction along top edge), direction (up, down, left, right) |
|
parallelogram |
skew (fraction or length), direction (right, left) |
Data, I/O. |
trapezoid |
inset (fraction), direction |
Manual operations. |
hexagon |
inset, orientation (flat, pointy) |
Preparation. |
octagon |
inset |
|
polygon |
sides, rotation, points (explicit fractional points) |
Regular or explicit polygon. |
star |
points, innerRadius (fraction), rotation |
|
cross |
thickness (fraction) |
Plus shape. |
cylinder |
cap (height of the ellipse cap), orientation (vertical, horizontal) |
Databases, storage. |
document |
wave (amplitude fraction) |
Wavy bottom. |
multiDocument |
wave, offset, count |
Stacked documents. |
note |
fold (size of the folded corner) |
Comments. |
folder |
tabWidth, tabHeight, tabPosition (left, right) |
Packages. |
frame |
tabWidth, tabHeight |
UML frames with name tab. |
cloud |
bumps |
External systems. |
process |
inset |
Predefined process (double side bars). |
delay |
– | D-shape. |
display |
– | Flowchart display. |
manualInput |
slope |
Sloped top. |
offPage |
pointer |
Pentagon pointing down. |
callout |
pointerX, pointerY (fractions, may lie outside 0–1), pointerWidth, radius |
Speech bubble with a tail. |
blockArrow |
direction, headLength, shaftThickness, doubleHeaded |
Arrow as a node. |
chevron |
depth, direction |
Process steps. |
actor |
– | Stick figure; label below by default. |
component |
– | UML component icon rectangle. |
line |
orientation (horizontal, vertical) |
A line node (separators, lifeline bodies). |
bracket |
side, curl |
Braces for annotations. |
text |
– | No visible body; just the label (free text). |
image |
src (Bindable URI), fit (contain, cover, fill, none), crop |
Image nodes. |
icon |
icon (IconRef), padding |
Icon filling the node. |
none |
– | Invisible body; used for pure containers or label-only elements. |
Every built-in shape defines its outline (for edge anchoring and hit testing) and its text area (where the main label goes). For example, a cylinder's text area excludes its top cap; an actor's text area lies below the figure.
When no primitive fits, a specification declares its own shapes in notation.shapes. A custom shape can be as simple as a static SVG path, or a fully parameterised, handle-editable shape whose geometry is computed with CEL.
| Property | Type | Description |
|---|---|---|
label, doc |
Shown in shape pickers and documentation. | |
params |
map → ShapeParam | Parameters (below). |
path |
PathDef | A single path (below). |
parts |
ShapePart[] | A composite of several shapes (below). |
svg |
string | Inline SVG markup scaled into the bounds (static shapes only). MUST be sanitised (section 16). |
plugin |
{name, args} |
Rendered by a plugin. |
outline |
"path", "bounds", "ellipse", PathDef |
Geometry used for edge anchoring and hit testing. Default: the path, or the union of parts marked outline: true. |
textArea |
Box | Where the main label is laid out, in shape coordinates. Default: the bounds minus padding. |
handles |
Handle[] | Interactive handles that edit parameters (below). |
defaultSize |
Size | Suggested size when used without an explicit node size. |
aspectRatio |
number | Fixed aspect ratio, if any. |
scaling |
ScaleMode | How static geometry maps into bounds (below). |
Exactly one of path, parts, svg or plugin MUST be present.
Shape coordinate context. Geometry expressions (GeomExpr, 2.5c) are evaluated with these variables:
| Variable | Type | Meaning |
|---|---|---|
w, h |
double | Width and height of the node's bounds in canvas units. |
p |
map | Resolved parameter values (p.fold). |
self |
Element | The model element (attributes available, read-only). |
env |
Env | Zoom, theme mode, locale. |
Coordinates are relative to the top-left of the bounds; x grows right, y grows down, regardless of the coordinate system orientation.
ShapeParam
| Property | Type | Description |
|---|---|---|
type |
"number", "int", "bool", "enum", "color", "string" |
Required. |
default |
value or {cel} |
Default value; CEL defaults may depend on w and h (for example "min(w, h) * 0.15"). |
min, max |
GeomExpr | Bounds; may depend on w and h. |
values |
string[] | For enum. |
unit |
"length", "fraction", "angle", "count" |
Semantics for property forms and handle behavior. |
label, doc |
Shown in the shape parameter panel. | |
persist |
"view", "none" |
Whether user-adjusted values (via handles or the style panel) are stored per element in view data. Default "view". |
PathDef — a path is either an SVG path string in a declared viewBox, scaled into the bounds, or a list of segments whose coordinates are GeomExprs:
{
"path": { "viewBox": [0, 0, 100, 60], "d": "M0 10 Q50 -10 100 10 L100 50 Q50 70 0 50 Z" }
}
{
"path": {
"segments": [
{ "op": "M", "x": 0, "y": 0 },
{ "op": "L", "x": "w - p.fold", "y": 0 },
{ "op": "L", "x": "w", "y": "p.fold" },
{ "op": "L", "x": "w", "y": "h" },
{ "op": "L", "x": 0, "y": "h" },
{ "op": "Z" }
]
}
}
op |
Fields | Meaning |
|---|---|---|
M |
x, y |
Move to. |
L |
x, y |
Line to. |
H, V |
x or y |
Horizontal or vertical line to. |
Q |
cx, cy, x, y |
Quadratic Bézier. |
C |
c1x, c1y, c2x, c2y, x, y |
Cubic Bézier. |
A |
rx, ry, rotation, largeArc, sweep, x, y |
Elliptical arc (SVG semantics). |
R |
x, y, w, h, r |
Rounded rectangle sub-path. |
E |
cx, cy, rx, ry |
Ellipse sub-path. |
Z |
– | Close. |
A path MAY have several sub-paths and a fillRule ("nonzero" default, "evenodd"). Each segment MAY carry when (Expression) to include it conditionally, which enables shapes whose topology depends on parameters (for example an optional double border).
ScaleMode controls how viewBox geometry and svg content fit the bounds: "stretch" (default), "uniform" (keep aspect ratio, centered), "none" (1:1 at the top-left), or { "nineSlice": [top, right, bottom, left] } — the corners of the viewBox keep their size and only the middle stretches, so rounded corners and tabs do not distort.
ShapePart — composite shapes combine parts, each of which is itself a shape (built-in or custom) with its own box and style. This is how an actor, a database with a label band, or a UML class header is composed.
| Property | Type | Description |
|---|---|---|
id |
identifier | Name of the part; styles and states can address parts (partStyles). |
shape |
ShapeRef | The part's shape. |
box |
{x, y, w, h} of GeomExpr |
Part bounds in shape coordinates. |
style |
StyleRef | Style of the part, merged over the node style. |
rotate |
GeomExpr | Rotation in degrees around the part's center. |
when |
Expression | Include only when true. |
outline |
bool | Part contributes to the connection outline. |
hit |
bool | Part is hit-testable. Default true. |
Handles let users fine-tune a shape directly on the canvas — dragging the fold of a note, the tail of a callout, the skew of a parallelogram — like the yellow diamonds of classic drawing tools.
| Property | Type | Description |
|---|---|---|
param |
param name | The parameter the handle edits. Required. |
x, y |
GeomExpr | Handle position in shape coordinates, computed from the current parameter values. |
axis |
"x", "y", "both", "radial" |
Direction the handle moves in. |
value |
Expression | Inverse mapping: computes the new parameter value from the pointer position px, py (shape coordinates), for example "w - px". Default: the pointer coordinate along axis. |
yParam, yValue |
param name, Expression | For two-parameter handles (axis: "both"). |
snap |
SnapRule | Snapping of the parameter value (for example { "grid": { "spacing": 2 } } or { "values": [0, 0.25, 0.5] }). |
cursor, style |
Handle appearance. | |
label, doc |
Tooltip while hovering or dragging ("Fold size: 14 px"). |
Example — a callout with a draggable tail and adjustable radius.
{
"shapes": {
"speech": {
"label": "Speech bubble",
"doc": "Drag the round handle to point the tail, the square handle to change the corner radius.",
"params": {
"tipX": { "type": "number", "unit": "fraction", "default": 0.2, "min": -0.5, "max": 1.5 },
"tipY": { "type": "number", "unit": "fraction", "default": 1.4, "min": -0.8, "max": 1.8 },
"base": { "type": "number", "unit": "fraction", "default": 0.3, "min": 0.1, "max": 0.8 },
"radius": { "type": "number", "unit": "length", "default": 8, "min": 0, "max": "min(w, h) / 2" }
},
"parts": [
{ "id": "body", "shape": { "type": "roundedRect", "params": { "radius": { "param": "radius" } } },
"box": { "x": 0, "y": 0, "w": "w", "h": "h" }, "outline": true },
{ "id": "tail",
"shape": { "path": { "segments": [
{ "op": "M", "x": "w * p.base", "y": "h - 1" },
{ "op": "L", "x": "w * p.tipX", "y": "h * p.tipY" },
{ "op": "L", "x": "w * (p.base + 0.15)", "y": "h - 1" },
{ "op": "Z" } ] } },
"box": { "x": 0, "y": 0, "w": "w", "h": "h" } }
],
"textArea": { "x": 10, "y": 8, "w": "w - 20", "h": "h - 16" },
"handles": [
{ "param": "tipX", "yParam": "tipY", "axis": "both",
"x": "w * p.tipX", "y": "h * p.tipY",
"value": "px / w", "yValue": "py / h", "label": "Tail tip" },
{ "param": "radius", "axis": "x", "x": "p.radius", "y": 0, "value": "px",
"snap": { "grid": { "spacing": 2 } }, "label": "Corner radius" }
]
}
}
}
Example — a static path from a viewBox with nine-slice scaling.
{
"ticket": {
"path": { "viewBox": [0, 0, 120, 60],
"d": "M8 0 H112 A8 8 0 0 0 120 8 V52 A8 8 0 0 0 112 60 H8 A8 8 0 0 0 0 52 V8 A8 8 0 0 0 8 0 Z" },
"scaling": { "nineSlice": [8, 8, 8, 8] }
}
}
notation.nodes maps node type names to NodeNotation objects.
| Property | Type | Description |
|---|---|---|
shape |
ShapeRef | Body shape. Default "rect". |
style |
StyleRef or StyleRef[] | Base style(s). |
partStyles |
map part id → StyleRef | Styles for parts of composite shapes. |
size |
SizeSpec | Default, minimum, maximum size and resize behavior (below). |
placement |
Placement | Coordinate binding (5.8). |
snapping |
Snapping | Per-type snapping override (5.9). |
rotation |
{allowed, default, step} |
Whether nodes may rotate; rotation is stored in view data. |
labels |
Label[] | Text labels (6.12). If absent, one centered label bound to the type's labelAttribute. |
compartments |
Compartment[] | Stacked regions listing items (below). |
form |
EmbeddedForm | Form widgets drawn inside the node (7.6). |
icon |
NodeIcon | Icon placement (below). |
badges |
Badge[] | Small indicators at corners or edges (below). |
ports |
map port name → PortNotation | Port visuals (below). |
anchors |
AnchorSpec | Where edges attach when no port is used (below). |
container |
ContainerSpec | How children are laid out and clipped (below). |
variants |
Variant[] | Conditional alternative notations (below). |
lod |
LodRule[] | Level of detail by zoom (below). |
states |
map state → Style | Interaction states (6.6). |
conditions |
{when, style, doc}[] |
Conditional styles (6.6). |
tooltip |
LocalizedText or {cel} |
Hover text. Default: the type's doc.summary. |
layer |
"background", "default", "foreground", or int |
Rendering layer (6.16). |
selectable, deletable, copyable, connectable |
Bindable bool | Interaction permissions (default true). |
hitPaddingScreenPx |
number | Extra hit area around the outline. |
doubleClick |
"editLabel", "openForm", "drillDown", "none", or operation name |
Double-click action. Default "editLabel". |
drillDown |
{viewpoint, filter} |
Open a sub-diagram (for example a sub-process) when drilling down. |
accessibility |
{role, name, description} |
Accessible name and description (6.15). |
doc |
Doc | Documents the notation itself ("Rounded corners mark states, circles pseudo-states"). |
SizeSpec
| Property | Type | Description |
|---|---|---|
default |
Size | Size on creation. |
min, max |
Size | Limits (null for unbounded in one dimension). |
fixed |
Size | Shorthand for default = min = max and not resizable. |
resizable |
bool, "horizontal", "vertical" |
Default true. |
aspectRatio |
number or "keep" |
Fixed ratio or keep the ratio of the default size while resizing. |
autoSize |
"none", "fitContent", "fitWidth", "fitHeight", "grow" |
Size follows content: labels, compartments, children, embedded forms. grow fits content but never shrinks below the user's size. |
width, height |
Bindable number | Computed or attribute-bound size in canvas units (for example a bar chart node). Placement width/x2 take precedence on bound axes. |
Compartments are stacked horizontal regions inside a node that list items — class attributes and operations, table columns, BPMN lanes' contents, checklist items.
| Property | Type | Description |
|---|---|---|
id |
identifier | Required. |
title |
LocalizedText | Optional header text. |
items |
{attribute}, {children}, or {cel} |
Source list: a many attribute, children of certain types ({ "children": ["Column"], "slot": "columns" }), or a CEL list. |
itemText |
Bindable string | Text per item; the context adds item and index. For child elements, a label binding writes back. |
itemIcon |
Bindable IconRef | Icon per item. |
itemStyle |
StyleRef | Style of every item. |
itemConditions |
{when, style}[] |
Conditional item styles; when sees item and index (for example primary-key columns underlined). |
layout |
"vertical" (default), "horizontal", "grid", "wrap" |
Arrangement of items. |
separator |
Stroke or "none" |
Line above the compartment. |
size |
"auto" or number or {min, max} |
Height. |
overflow |
"grow", "clip", "scroll", "ellipsis" |
When items exceed max. ellipsis shows "… 3 more". |
maxItems |
int | Items shown before overflow. |
collapsible, collapsed |
bool, Bindable bool | Collapse state persisted in view data. |
emptyText |
LocalizedText | Placeholder when empty. |
editable |
{add, remove, reorder, inline} of bool |
In-place editing of items. |
visible |
Bindable bool | |
padding, style |
NodeIcon: { "icon": IconRef, "position": Position, "size": 16, "color": Paint, "visible": Bindable }. Badge: { "id", "position": Position, "offset": [dx, dy], "shape": ShapeRef, "text": Bindable string, "icon": IconRef, "style": StyleRef, "size", "visible": Bindable bool, "tooltip", "onClick": operation } — for example a problem counter, a lock, a stereotype glyph, a progress ring.
Positions inside a node are one of "center", "top", "bottom", "left", "right", "top-left", "top-right", "bottom-left", "bottom-right", the same prefixed with outside- (for example "outside-bottom" below the node, as for actors and events), or an object { "anchor": [fx, fy], "offset": [dx, dy], "align": "center" }.
Ports notation
| Property | Type | Description |
|---|---|---|
shape |
ShapeRef | Port shape. Default "rect" 8 × 8. |
size |
Size | |
style, states |
||
side |
"top", "right", "bottom", "left", "auto", Bindable |
Side of the node. auto chooses by direction (in = left, out = right) in the layout direction. |
position |
Bindable fraction or "distribute" |
Position along the side; distribute spaces all instances evenly. Default "distribute". |
inset |
number | Offset from the outline: negative = outside, 0 = centered on the outline, positive = inside. |
movable |
bool | Users may drag ports along the outline (positions stored in view). |
label |
Label | Port label; default position "outside" of the side. |
order |
Expression | Sort key for distributed ports. |
AnchorSpec — when edges attach to the node itself (not a port):
| Property | Type | Description |
|---|---|---|
mode |
"outline", "center", "fixed", "sides" |
outline (default): intersection of the line towards the center with the outline; center: all edges aim at the center; fixed: only at listed points; sides: at the midpoint of the nearest side (orthogonal diagrams). |
points |
{id, x, y}[] |
Fixed anchor points as fractions of the bounds. |
gap |
number | Distance between the outline and the edge end. |
spread |
bool | Distribute several edges arriving on the same side instead of converging on one point. |
ContainerSpec — for nodes whose type has children:
| Property | Type | Description |
|---|---|---|
layout |
"free", "stack", "grid", "flow", "lanes", "layout:<name>" |
Arrangement of children. lanes splits the container into bands (pools with lanes). layout:<name> delegates to a named layout (section 10). |
direction |
"vertical", "horizontal" |
For stack, flow and lanes. |
gap, padding |
number, Insets | |
columns |
int | For grid. |
header |
{size, side, label, style} |
Header band (title bar of a group, vertical name band of a BPMN pool on side: "left"). |
contentArea |
Box | Area children are placed in, in node coordinates. |
clip |
bool | Clip children to the content area. |
autoGrow |
bool | Grow when children are moved to the edge. |
collapsible |
bool | Collapsing hides children and optionally switches to a collapsed variant. |
dropZones |
{slot, box, style}[] |
Explicit regions that accept children of a slot (4.8). |
highlightOnDrop |
bool | Apply the dropTarget state while a valid child is dragged over. |
Variants switch whole parts of a notation based on model state — for example a collapsed sub-process, an event rendered differently when interrupting, a gateway symbol that depends on its kind:
{
"variants": [
{ "when": "self.kind == 'exclusive'", "doc": "XOR gateway shows an ×.",
"icon": { "icon": "std.x", "position": "center", "size": 18 } },
{ "when": "self.kind == 'parallel'",
"icon": { "icon": "std.plus", "position": "center", "size": 18 } },
{ "when": "self.view.collapsed", "shape": "roundedRect", "size": { "fixed": [120, 60] }, "compartments": [] }
]
}
A Variant may contain any NodeNotation property except placement; matching variants are applied in order over the base notation.
Level of detail (lod) implements semantic zoom: [ { "maxZoom": 0.3, "hide": ["compartments", "badges", "form"], "labels": "primary", "shape": "rect" }, { "maxZoom": 0.1, "render": "box" } ]. hide lists notation properties or label ids; render: "box" draws a plain filled rectangle for performance.
notation.edges maps relation type names — and optionally Type.attribute names for reference attributes that should be drawn as edges — to EdgeNotation objects.
| Property | Type | Description |
|---|---|---|
line |
LineSpec | Stroke, routing and geometry (below). |
style |
StyleRef | Style whose stroke and font apply to line and labels. |
sourceMarker, targetMarker |
MarkerRef or Bindable | Arrowheads and end decorations (6.11). Default: none at source, arrowFilled at target for directed relations. |
midMarkers |
MidMarker[] | Decorations along the edge (below). |
labels |
EdgeLabel[] | Labels at start, middle, end or any fraction (6.12). |
anchoring |
{source, target} of EndAnchor |
How ends attach (below). |
selfLoop |
SelfLoopSpec | Geometry of self loops. |
parallel |
{spread, mode} |
How parallel edges between the same nodes are separated: spread distance and mode ("offset", "curve", "bundle"). |
jumps |
JumpSpec | How this edge crosses others. |
snapping |
Snapping | Bendpoint snapping override. |
hitWidthScreenPx |
number | Width of the hit area. Default 8. |
layer |
"belowNodes", "aboveNodes", int |
Rendering layer (6.16). Default "belowNodes". |
states, conditions, variants |
As for nodes; variants may replace line, markers and labels. | |
tooltip, selectable, deletable, reconnectable |
reconnectable controls whether users may drag an end to another element. |
|
accessibility, doc |
LineSpec
| Property | Type | Description |
|---|---|---|
stroke |
Stroke | Everything from 6.4: color, width, dash, caps, double, casing, effect, flow, sketch. |
routing |
Routing | "straight" (default), "polyline" (user bendpoints), "orthogonal" (horizontal/vertical segments), "rounded" (orthogonal with rounded corners), "curved" (smooth curve through bendpoints), "bezier" (cubic with editable control points), "spline" (Catmull-Rom through points), "arc" (single circular arc), "tree" (fork from a common trunk), "metro" (octilinear: 0°/45°/90°), "layout" (from the layout algorithm), or { "plugin": … }. |
cornerRadius |
number | Rounding for orthogonal, metro and polyline. |
curvature |
number | For arc and curved (0 = straight, 1 = semicircle). |
avoidNodes |
bool | Route around nodes that are not endpoints. |
avoidPadding |
number | Clearance around avoided nodes. |
bendpoints |
{editable, max, addOnDrag, removeOnStraighten} |
User editing of bendpoints; removeOnStraighten merges collinear points. |
segments |
{editable, keepOrthogonal} |
Dragging whole segments of orthogonal edges. |
minSegmentLength |
number | Minimum length of the first and last segment (so markers do not sit on a corner). |
startDirection, endDirection |
"auto", "up", "down", "left", "right", "normal" |
Direction the line leaves or enters its node; normal is perpendicular to the outline. |
JumpSpec: { "style": "none" | "arc" | "gap" | "square" | "sharp", "size": 6, "over": "later" | "horizontal" | "all" } — draws a small bridge where this edge crosses another. over decides which of two crossing edges jumps: the later-drawn one (default), always the horizontal one, or both.
EndAnchor: { "mode": "outline" | "center" | "port" | "fixed" | "sides", "gap": 2, "points": [...] } overrides the node's AnchorSpec for this edge type; gap leaves space between the node outline and the marker.
SelfLoopSpec: { "shape": "arc" | "rect" | "circle", "size": 30, "side": "top" | "right" | "bottom" | "left" | "auto", "spread": 10 }.
MidMarker — decorations anywhere along the path:
| Property | Type | Description |
|---|---|---|
marker |
MarkerRef | The decoration. |
at |
fraction, "middle", "start", "end" |
Position along the path length. Default "middle". |
repeat |
{spacing, from, to} |
Repeat every spacing canvas units within the range. |
orient |
"auto", "auto-reverse", angle |
Rotation relative to the path tangent. |
visible |
Bindable bool |
Example — a richly decorated edge.
{
"edges": {
"Association": {
"line": {
"stroke": { "color": { "token": "color.border" }, "width": 1.25,
"dash": { "cel": "self.derived ? 'dashed' : 'solid'" },
"casing": { "color": { "token": "color.surface" }, "width": 5 } },
"routing": "rounded", "cornerRadius": 6, "avoidNodes": true,
"bendpoints": { "editable": true, "removeOnStraighten": true },
"minSegmentLength": 16
},
"jumps": { "style": "arc", "size": 5 },
"sourceMarker": { "cel": "self.sourceAggregation == 'composite' ? 'diamondFilled' : (self.sourceAggregation == 'shared' ? 'diamond' : 'none')" },
"targetMarker": { "cel": "self.navigable ? 'arrow' : 'none'" },
"labels": [
{ "id": "name", "text": { "attribute": "name" }, "at": "middle", "side": "above", "editable": "inline" },
{ "id": "srcRole","text": { "attribute": "sourceRole" }, "at": "start", "offset": 12, "side": "above", "editable": "inline" },
{ "id": "srcMul", "text": { "attribute": "sourceMultiplicity" }, "at": "start", "offset": 12, "side": "below" },
{ "id": "tgtRole","text": { "attribute": "targetRole" }, "at": "end", "offset": 12, "side": "above", "editable": "inline" },
{ "id": "tgtMul", "text": { "attribute": "targetMultiplicity" }, "at": "end", "offset": 12, "side": "below" }
],
"states": { "selected": { "stroke": { "color": { "token": "color.accent" }, "width": 2 } } }
}
}
}
A marker is drawn at an edge end (or along the edge) and oriented along the path tangent. References are a name, a name with parameters, or an inline declaration:
{
"targetMarker": "arrowFilled",
"targetMarker": { "type": "arrow", "params": { "length": 12, "width": 10, "angle": 30 } },
"targetMarker": { "type": "stack", "markers": ["bar", "erMany"], "spacing": 3 },
"targetMarker": { "cel": "self.optional ? 'erZeroOrMany' : 'erOneOrMany'" }
}
Built-in markers (details and default sizes in Appendix B.3):
| Group | Markers |
|---|---|
| Arrows | arrow (open V), arrowFilled (solid triangle), arrowHollow (outlined triangle, UML generalisation), arrowConcave (swept-back barbed head), arrowThin, arrowDouble (two heads), halfArrowTop, halfArrowBottom (asynchronous messages), arrowCircle |
| Geometric | diamond, diamondFilled, circle, circleFilled, square, squareFilled, dot, triangle, triangleFilled |
| Lines | bar (perpendicular line), doubleBar, cross (×), slash |
| Crow's foot (ER) | erOne, erOnlyOne, erMany, erZeroOrOne, erOneOrMany, erZeroOrMany |
| UML and engineering | ballSocketBall (provided interface), socket (required interface), containment (circled plus), ground, fork |
| Other | none |
Marker parameters (all optional, Bindable):
| Parameter | Description |
|---|---|
length |
Size along the path (canvas units). |
width |
Size across the path. |
angle |
Half-opening angle of arrows, in degrees. |
scaleWithStroke |
Scale with the line width (default true, relative to width 1). |
fill |
Paint, or "stroke" (same as line color, default for filled markers) or "background" (canvas or token color.surface, default for hollow markers so the line does not show through). |
stroke |
Stroke of the marker outline; default inherits the line's color and width, never its dash. |
inset |
Distance from the edge end point (move the marker back). |
shorten |
How far the line is shortened so it ends inside the marker rather than poking through its tip. Default: computed per marker. |
minSizeScreenPx |
Minimum on-screen size when zoomed out. |
Custom markers in notation.markers:
| Property | Type | Description |
|---|---|---|
path |
PathDef | Geometry in marker coordinates: x points along the path tangent towards the end, the tip is at the reference point. |
parts |
ShapePart[] | Composite marker. |
ref |
[x, y] |
Reference point placed exactly at the edge end. Default [0, 0]. |
size |
[length, width] |
Nominal size (scales viewBox geometry). |
params |
map → ShapeParam | Parameters, used in GeomExprs as p.<name> (plus sw = stroke width). |
orient |
"auto", "auto-start-reverse", angle |
Default "auto"; source markers are automatically reversed. |
fill, stroke |
Paint, Stroke | Defaults as above. |
shorten |
GeomExpr | Line shortening. |
label, doc |
Shown in marker pickers and generated docs. |
{
"markers": {
"chevronPair": {
"label": "Double chevron",
"doc": "Signals a streamed (continuous) flow.",
"params": { "gap": { "type": "number", "default": 4 } },
"path": { "segments": [
{ "op": "M", "x": -10, "y": -5 }, { "op": "L", "x": 0, "y": 0 }, { "op": "L", "x": -10, "y": 5 },
{ "op": "M", "x": "-10 - p.gap", "y": -5 }, { "op": "L", "x": "-p.gap", "y": 0 }, { "op": "L", "x": "-10 - p.gap", "y": 5 } ] },
"fill": "none",
"shorten": 0
}
}
}
Stacked markers (type: "stack") compose several markers from the end inward with a spacing, for example bar + erMany for "one or many" in some ER dialects, or an arrow followed by a circle.
Labels display text on nodes, edges, ports and compartments. The same Label object is used everywhere; edges add path-relative positioning.
| Property | Type | Description |
|---|---|---|
id |
identifier | Unique within the notation; used in view data (label offsets), lod.hide and styles. |
text |
Bindable string or { "attribute": … } |
Content. Attribute bindings make the label editable. |
format |
"plain", "markdown", "rich" |
markdown renders a safe inline subset (emphasis, code, links); rich enables spans from { "cel": … } returning a list of {text, style}. |
placeholder |
LocalizedText | Shown (dimmed) when text is empty and the element is selected. |
editable |
false, "inline", "multiline", "form" |
How users edit the text; form opens the field in the form. Requires an attribute binding. Default: "inline" for attribute bindings, else false. |
parse |
{cel, write} |
Parse edited text into several attributes (for example "name : Type" → name, type), with value = entered text and write actions (9.4). |
position |
Position | For nodes and ports (6.9). |
style |
StyleRef | Font, color, alignment. |
background |
{fill, stroke, padding, cornerRadius} |
Box behind the text (tags, pills). |
maxWidth |
number or "parent" |
Wrap width. |
wrap |
"none", "word", "char" |
Default "word" for node labels, "none" for edge labels. |
maxLines |
int | |
overflow |
"visible", "clip", "ellipsis", "shrink" |
shrink reduces font size down to font.minSizeScreenPx. |
rotation |
angle or "vertical" |
Vertical text for lane headers. |
icon |
IconRef | Icon before the text. |
visible |
Bindable bool | |
draggable |
bool | Users may move the label; the offset is stored in view data. Default true for edge labels, false for node labels. |
link |
Bindable URI | Clickable label. |
layer |
"top" |
Draw the label above all elements (6.16) so it is never covered. |
tooltip, doc |
Edge label positioning — for labels in EdgeNotation.labels:
| Property | Type | Description |
|---|---|---|
at |
"start", "middle", "end", or fraction |
Anchor along the path. start and end are measured from the visible ends (after markers). Default "middle". |
offset |
number | Distance along the path from the anchor, in canvas units (towards the middle for start/end). |
side |
"above", "below", "left", "right", "on" |
Side of the line relative to its direction. on centers the label on the line (with a background that interrupts it). |
distance |
number | Perpendicular distance from the line. Default 4 plus half the label height. |
orientation |
"horizontal", "follow", "upright" |
Keep text horizontal (default), rotate along the path, or rotate but never upside down. |
avoidMarkers |
bool | Push start/end labels clear of markers. Default true. |
keepOnSegment |
bool | For orthogonal routes, keep start/end labels on the first/last segment. |
Together, at and side place labels in any of the conventional slots:
Diagram as text (Mermaid)
block-beta
columns 5
startAbove["start-above"] space middleAbove["middle-above"] space endAbove["end-above"]
start(("start")) space middle["middle"] space finish(("end"))
startBelow["start-below"] space middleBelow["middle-below"] space endBelow["end-below"]
start --- middle
middle --> finish
classDef slot fill:none,stroke:none
class startAbove,middleAbove,endAbove,startBelow,middleBelow,endBelow slotnotation.canvas (or a viewpoint's canvas) configures the drawing surface:
| Property | Type | Description |
|---|---|---|
background |
Paint | Canvas background (default token color.canvas). |
page |
{size, orientation, margins, showBreaks} |
Paged canvas for printing: size "A4", "Letter", [w, h] in mm. |
bounds |
Box | Fixed drawing area. |
zoom |
{min, max, default, steps} |
Zoom limits and presets. |
watermark |
Label | Text drawn under everything (for example "DRAFT" when diagram.status == 'draft'). |
legend |
{visible, position, entries} |
Auto-generated legend of types, markers and conditional styles that carry doc. |
minimap |
bool | Show an overview map. |
selection |
{style, handles} |
Selection outline and resize handle appearance. |
notation.icons declares icons used by tools, nodes, badges and labels.
| Form | Example |
|---|---|
| Inline SVG | { "svg": "<svg viewBox='0 0 24 24'>…</svg>" } (sanitised) |
| Path | { "path": { "viewBox": [0,0,24,24], "d": "M…" }, "stroke": true } |
| Image | { "src": "icons/db.png", "size": [24, 24] } |
| Icon font glyph | { "font": "tabler", "glyph": "database" } |
| Library | "std.database" or "tabler:database" |
Icons are monochrome by default and take currentColor, so they follow the theme; colored: true keeps their own colors.
Notations SHOULD make diagrams accessible:
accessibility.name(Bindable string) names each element for screen readers; the default is the type label pluslabelAttribute.accessibility.descriptiondescribes relations (default: "Transition from Idle to Running, trigger start").- Runtimes SHOULD provide keyboard navigation between elements and along edges, and expose the model as an accessible tree.
- Color MUST NOT be the only carrier of meaning in built-in defaults; specifications SHOULD pair color with shape, pattern, dash, icon or text. Validators MAY warn when two types differ only in fill color.
- Themes SHOULD provide a
high-contrastmode; runtimes SHOULD honour reduced-motion settings (disableflowanimations).
Elements are drawn in layers: canvas background → grid and bands → background layer nodes → edges with layer: "belowNodes" → default nodes (containers before their children; siblings by zIndex in view data, then by stored order) → edges with layer: "aboveNodes" → foreground nodes → labels that are marked layer: "top" → selection, handles, guides and snapping feedback. Integer layers sort numerically between these named layers (background = −100, default = 0, foreground = 100).
Illustrated by
- Entity–relationship diagram: 4 items in this layer
- State machine: 15 items in this layer
- Project timeline: 6 items in this layer