14  Diagram and Configuration Reference

See Core Concepts and Configuration and Scoping for the narrative version.

14.1 diagram()

typ.diagram(
  body,
  scale: auto,
  grid: auto,
  font-size: auto,
  node-styles: auto,
  edge-styles: auto,
  inset: auto,
  scale-edges: auto,
  port-spacing: auto,
  anchor: auto,
  math-axis: auto,
  baseline: auto,
  theme: typ.neutral-theme,
)
Argument Meaning
body Evaluates to an array of diagram items; none is an empty diagram.
theme The explicit, atomic theme value. Never inherited from config().
scale Coordinate unit and overall zoom. A number is a multiple of 1cm; a length is exact. Node sizes, labels, strokes, and coordinates all follow it.
scale-edges Positive multiplier applied only to coordinate spacing — lengthens wires without enlarging nodes.
port-spacing Positive length between neighboring gate ports. Defaults to 7pt; a gate’s own port-spacing: wins.
grid Boolean; true overlays a light integer coordinate grid, useful while authoring.
font-size auto or a positive length; sets node/edge label size. A node’s style.font-size or an edge’s style.label-size wins over this for that one label.
node-styles Maps kinds to partial node styles, for this diagram only.
edge-styles Partial edge style applied to every edge in this diagram.
inset Diagram margin. A number is diagram units; a length is independent of zoom (em resolves against surrounding text). A side dictionary (left/right/top/bottom/x/y/rest) is accepted; unknown keys error.
anchor Numeric diagram y-coordinate placed on the math axis (normally 0).
math-axis Length, normally 0.25em.
baseline auto, or a length overriding the computed shift directly.

Everything left auto inherits from the nearest config() scope, then the built-in defaults. theme is not part of that inheritance chain.

Inside config(), auto also preserves the enclosing value, except font-size: auto and baseline: auto, which explicitly restore document font sizing and the calculated baseline respectively.

14.1.1 Sizing: zoom vs. wire length vs. margin

  • scale zooms everything — nodes, labels, and stroke widths all scale together, so a diagram shrunk to fit a figure keeps its proportions instead of turning into heavy strokes around tiny nodes.
  • scale-edges stretches only the coordinate grid: wires lengthen, nodes and labels stay the same physical size.
  • inset is the margin around the whole diagram, in the same number-or-length-or-side-dictionary shape used everywhere else in the package (see Node style keys).

The accepted dictionary shape is shared, but numeric units differ:

Value Unit and scaling
diagram(inset: 2) Two coordinate units; follows scale and scale-edges.
diagram(inset: 2pt) Two absolute points; unaffected by either zoom knob.
diagram(inset: 0.5em) Half the surrounding text size; unaffected by either zoom knob.
Node style: (inset: 2) or (inset: 2pt) Two points at reference scale; follows node zoom, not scale-edges.
Edge style: (label-inset: 2pt) Two reference-scale points; follows edge zoom. Ratios/relative lengths are also supported; unitless numbers are not.

To assert geometry with measure(diagram(...)), use baseline: 0pt: the normal math-axis baseline can add vertical line-box extent, especially for empty diagrams. This does not affect the diagram’s width.

14.1.2 Font-relative lengths

Geometric lengths may contain em: node minima/insets/radii, gate sizes and port spacing, strokes, highlight widths/offsets, label insets/offsets, and decorative-part and mark dimensions. They resolve against the surrounding text size, before diagram/group zoom. A label’s own font-size override does not change its node’s geometric em. Percentage components remain relative to their normal reference dimension; only the length component is zoomed.

#set text(size: 10pt)
#typ.diagram(scale: 2, typ.edge(
  typ.node(0, 0, style: (shape: typ.shapes.diamond, min-size: 2em)),
  (2, 0), stroke: 0.1em + black,
))

Here the node’s pre-zoom minimum is 20pt and the wire’s pre-zoom thickness is 1pt. Mixed lengths such as 2em - 5pt are validated after resolution: dimensions must remain non-negative, and font sizes/port spacing/scale must remain positive. Pure constructors can be called outside context; diagram() supplies context for layout. Standalone node-outline() needs context for either text measurement or geometric em resolution.

14.2 config()

typ.config(
  body,
  scale: .., scale-edges: .., port-spacing: .., font-size: .., grid: .., inset: ..,
  anchor: .., math-axis: .., baseline: ..,
  node-styles: .., edge-styles: ..,
)

Accepts exactly the non-theme diagram() arguments above. node-styles merges one level by kind; edge-styles merges shallowly; other concrete values replace outright. The auto exceptions are described above. Scopes nest and revert; see Configuration and Scoping for the nesting semantics and the two alternative mechanisms (diagram.with(..), #set text(..)).

14.3 Exported resolver helpers

typ.resolve-node-style(kind, presets, ..overrides) and typ.resolve-edge-style(edge, overrides, presets: (:), defaults: (:)) are the pure functions the renderer itself uses to walk the precedence chains described in Core Concepts. They’re exposed for tests and advanced integration; an ordinary document should let diagram() perform resolution internally, so the same resolved style is guaranteed to be shared by bounds, drawing, clipping, and ports — calling a resolver yourself and also letting diagram() resolve independently risks the two falling out of sync.