Skip to content

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.

6.1 Overview and resolution

{
  "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:

  1. Per-element style override stored in the DID definition's view data (11.6), if the specification allows overrides.
  2. Interaction state styles (states.selected, states.hover, …) that are active, in the fixed priority dragging > selected > focused > hover > highlighted > dropTarget > invalid > warning > disabled.
  3. Conditional styles (conditions) whose when expression is true, in declaration order (later wins).
  4. Variants (variants) whose when is true — they may replace shape, size, labels and style.
  5. The notation's own style (inline or referenced), with extends chains resolved.
  6. The notation of the nearest supertype (C3 order), repeating steps 2–5.
  7. The viewpoint override and then the global notation.defaults for the element kind.
  8. The built-in default (Appendix B.1).

Properties merge per key: a state style that only sets stroke.color keeps the resolved stroke.width.

6.2 Theme and tokens

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.

6.3 Paint

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.

6.4 Stroke and line styles

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).

6.5 Text and fonts

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.

6.6 Styles

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" }
  ]
}

6.7 Shapes: built-in primitives

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.

6.8 Custom shapes

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] }
  }
}

6.9 Node notation

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.

6.10 Edge notation

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 } } }
    }
  }
}

6.11 Markers (arrowheads and end decorations)

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.

6.12 Labels

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:

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 slot

6.13 Canvas

notation.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.

6.14 Icons

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.

6.15 Accessibility

Notations SHOULD make diagrams accessible:

  • accessibility.name (Bindable string) names each element for screen readers; the default is the type label plus labelAttribute.
  • accessibility.description describes 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-contrast mode; runtimes SHOULD honour reduced-motion settings (disable flow animations).

6.16 Rendering order

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

Referenced from