composite shapes

Composite shapes hold or lay out content rather than drawing a single primitive — a container frames child shapes, a card embeds rich wdoc content, and a node_table builds a row-table with per-row connection ports. Each leads with its own preview.

§ 1container

A container frames its children and can lay them out automatically (here a 2-column grid):

Preview

Example

diagram {
  width = 240
  height = 130
  container {
    anchor_left = 10.0
    anchor_top = 10.0
    fill = "#eef"
    stroke = "#88a"
    padding = 10.0
    layout = :grid
    columns = 2
    cell_width = 90.0
    cell_height = 44.0
    gap = 10.0
    rect {
      fill = "#88c0d0"
    }
    rect {
      fill = "#a3be8c"
    }
    rect {
      fill = "#ebcb8b"
    }
    rect {
      fill = "#b48ead"
    }
  }
}

A titled box that groups and frames child shapes.

PropertyTypeRequiredDescription
ididentifiernoName used to connect the shape (a -> b) and to anchor others to it.
classlist<utf8>noStyle classes — text and SVG paint via the class system.
linkutf8noLink the shape to an in-site page (bare page name, or site:page). Wraps it in a clickable <a>; an unknown page fails the build like a bad prose link.
strokeutf8noOptional chrome — outline colour of the background rect that makes the group visible.
fillutf8noOptional chrome — fill colour of the background rect that makes the group visible.
paddingf64noInset between the chrome and the child shapes.
widthf64noDeclared interior width (when no layout/anchor sizes it).
heightf64noDeclared interior height (when no layout/anchor sizes it).
layoutsymbolnoLayout mode: :free (default, manual) / :grid / :layered / :force / :radial.
columnsi64noNumber of columns for :grid layout.
cell_widthf64noGrid cell width for :grid layout.
cell_heightf64noGrid cell height for :grid layout.
gapf64noGap between cells in :grid layout.
directionsymbolnoFlow direction for :layered: :top_to_bottom (default) / :left_to_right.
layer_gapf64noSpacing between ranks (layers) in :layered layout.
node_gapf64noSpacing between nodes within a rank in :layered layout.
iterationsi64no:force relaxation steps (default 300).
repulsionf64no:force node repulsion strength (default 9000).
link_distancef64no:force ideal edge-to-edge length (default 60).
gravityf64no:force centering pull (default 0.05).
seedi64no:force random seed for reproducible layouts (default 1).
hubidentifierno:radial hub shape id (defaults to the highest-degree shape).
radiusf64no:radial radius of the first ring (default: auto-fit to shape sizes).
ring_gapf64no:radial added radius per successive ring (default 120).
start_anglef64no:radial angle (radians) of the first shape on each ring (default -PI/2, i.e. top).
anchor_leftf64noFractional anchor (0–1) pinning the left edge to the parent box.
anchor_rightf64noFractional anchor (0–1) pinning the right edge to the parent box.
anchor_topf64noFractional anchor (0–1) pinning the top edge to the parent box.
anchor_bottomf64noFractional anchor (0–1) pinning the bottom edge to the parent box.
connect_pointslist<AnchorSide>noWhich sides (:left/:right/:top/:bottom) edges attach to.
iconutf8noIcon-badge icon (a pack.name).
icon_sizef64noIcon-badge size.
icon_posIconPosnoIcon-badge position (:center / :top_left / …).
icon_classlist<utf8>noIcon-badge style classes.
edgeslist<Edge>yesEdges connecting child shapes (a -> b).

Child blocks

SlotAcceptsMultipleDescription
childrenSvgBlockyesThe child shapes laid out by the container.

§ 2card

A card's body is rich wdoc content (paragraphs, lists, even nested diagrams), drawn in a foreignObject:

Preview

Note

Rich text inside a diagram.

Note

Rich text inside a diagram.

Example

diagram {
  width = 260
  height = 110
  card {
    x = 20.0
    y = 15.0
    width = 220.0
    height = 80.0
    title = "Note"
    p "Rich **text** inside a diagram."
  }
}

A box whose body is rich wdoc content (paragraphs, lists, nested diagrams), drawn in a foreignObject.

PropertyTypeRequiredDescription
xf64noTop-left x placement in the diagram (or use anchors).
yf64noTop-left y placement in the diagram (or use anchors).
widthf64noCard box width (default 160).
heightf64noCard box height (default 90).
anchor_leftf64noDiagram anchor insets (left/right/top/bottom), like any shape.
onutf8noISO date the card is pinned to (used only when it's a timeline child).
sidesymbolnoTimeline side: :near / :far / :auto (used only as a timeline child).
titleutf8noOptional plain-text heading.
ididentifiernoOptional explicit HTML id.
classlist<utf8>noOptional style classes.
connect_pointslist<AnchorSide>noDiagram edge-attach sides, like any shape.

Child blocks

SlotAcceptsMultipleDescription
bodyWdocBlockyesThe card's rich content (paragraphs, lists, callouts, nested diagrams…).

§ 3node_table

Two node_tables joined by a foreign-key edge that targets a single row:

Preview

users

id: int

email: text

orders

id: int

user_id: int

users

id: int

email: text

orders

id: int

user_id: int

Example

diagram {
  width = 420
  height = 170
  routing = :straight
  node_table {
    id = users
    x = 20.0
    y = 20.0
    width = 150.0
    title = "users"
    node_row {
      id = users_id
      p "id: int"
    }
    node_row {
      id = users_email
      p "email: text"
    }
  }
  node_table {
    id = orders
    x = 250.0
    y = 20.0
    width = 150.0
    title = "orders"
    node_row {
      id = orders_id
      p "id: int"
    }
    node_row {
      id = orders_user_id
      p "user_id: int"
    }
  }
  orders_user_id -> users_id :data
}

A row-table shape for DB / class diagrams, with per-row connection ports.

PropertyTypeRequiredDescription
xf64noTop-left x placement in the diagram (or use anchors).
yf64noTop-left y placement in the diagram (or use anchors).
widthf64noTable width (default 200). Height is derived from the rows.
anchor_leftf64noDiagram anchor insets (left/right/top/bottom), like any shape.
titleutf8noOptional header title (table / class name). Omit for a header-less table.
header_heightf64noHeader row height when a title is set (default 28).
row_heightf64noFixed height of every row (default 30). The renderer can't measure HTML, so rows don't auto-size.
ididentifiernoOptional explicit HTML id (edge target for the whole table).
classlist<utf8>noOptional style classes (applied to the frame).
connect_pointslist<AnchorSide>noWhole-table edge-attach sides (default all four). Per-row sides come from each node_row.

Child blocks

SlotAcceptsMultipleDescription
rowsnode_rowyesThe table rows, top to bottom.

One row of a node_table.

PropertyTypeRequiredDescription
ididentifiernoRow id — the edge target for connecting to this row (fk -> users_id).
classlist<utf8>noOptional style classes (applied to the row content).
connect_pointslist<AnchorSide>noSides this row exposes a connection point + marker on (default [:west, :east]).

Child blocks

SlotAcceptsMultipleDescription
bodyWdocBlockyesThe row's rich content (paragraphs, code, lists…).