15 Node Reference
See Drawing Nodes for the narrative version.
15.1 Generic constructors
All single-node constructors below accept either x, y or one point. A point is a coordinate pair, node center, port, named reference, or offset. Each separate axis may be numeric or a deferred .x/.y coordinate. Examples: node(p), box(p, label: [A]), gate(p, [U]), and make-node("custom", p). Existing numeric calls and partial application remain supported. See Relative positioning.
typ.node(x, y, label: none, name: none, style: (:), kind: "node", base-style: (:))Fully general; neutral default is shapes.empty.
typ.box(x, y, label: none, fill: auto, stroke: auto, inset: auto, radius: auto, name: none, style: (:))Generic rectangle; direct appearance arguments layer at the call site.
typ.gate(
x, y, label,
legs: (left: 1, right: 1),
max-legs-per-side: none,
port-spacing: auto,
size: auto,
inset: auto,
name: none,
style: (:),
kind: "gate",
)Labelled, port-capable. legs values are non-negative integers; automatic minimum size grows only when an axis has multiple ports, using their exact center spacing plus the gate margin: (count - 1) * spacing + 12pt horizontally and (count - 1) * spacing + 9pt vertically, with the lengths scaled by the diagram. A lone port leaves the styled minimum untouched. size: accepts one non-negative length for a square or a (w, h) pair and overrides it. Unlabeled gates contribute no implicit label inset, so compact theme minima are not floored by generic gate padding. max-legs-per-side (when not none) rejects any side with too many ports. port-spacing: sets an exact positive distance between neighboring port centers; auto inherits the diagram/config value. kind: selects the theme preset independently of port capability.
measurement(x, y, label: none, name: none, style: (:), legs: (right: 1), max-legs-per-side: 1, port-spacing: auto)
state(x, y, label: none, name: none, style: (:), legs: (right: 1), port-spacing: auto)
effect(x, y, label: none, name: none, style: (:), legs: (left: 1), port-spacing: auto)
discard(x, y, label: none, name: none, style: (:), legs: (left: 1), max-legs-per-side: 1)
control(
x, y, label: none,
name: none,
style: (:),
size: auto,
legs: (right: 1),
max-legs-per-side: 1,
flip: auto,
)
target(
x, y, label: none,
name: none,
style: (:),
size: auto,
legs: (left: 1),
max-legs-per-side: 1,
flip: auto,
)
cnot(
control-x,
control-y,
target-x,
target-y,
control-label: none,
target-label: none,
control-style: (:),
target-style: (:),
wire-style: (:),
control-size: auto,
target-size: auto,
control-legs: (right: 1),
target-legs: (left: 1),
max-legs-per-side: 1,
)
control_dot(
x, y,
label: none,
name: none,
style: (:),
size: auto,
legs: (right: 1),
max-legs-per-side: 1,
flip: auto,
)
open_control(
x, y,
label: none,
name: none,
style: (:),
size: auto,
legs: (right: 1),
max-legs-per-side: 1,
)
swap(
x, y,
label: none,
name: none,
style: (:),
flip: auto,
)
ancilla(x, y, label: none, name: none, style: (:))
unitary(
x, y, label,
name: none,
style: (:),
legs: (left: 1, right: 1),
max-legs-per-side: none,
port-spacing: auto,
size: auto,
inset: auto,
)
phase(x, y, label: none, name: none, style: (:), legs: (left: 1, right: 1), max-legs-per-side: 1)
cz(control-x, control-y, target-x, target-y, control-style: (:), target-style: (:), wire-style: (:), control-size: auto, target-size: auto)
cswap(control-x, control-y, upper-x, upper-y, lower-x, lower-y, control-style: (:), upper-style: (:), lower-style: (:), wire-style: (:), control-size: auto)
barrier(x, start-y, end-y, style: (:))
input_label(x, y, body)
output_label(x, y, body)
displacement(x, y, label: [$D(alpha)$], name: none, style: (:), legs: (left: 1, right: 1))
squeezer(x, y, label: [$S(z)$], name: none, style: (:), legs: (left: 1, right: 1))
phase_shift(x, y, label: [$R(phi)$], name: none, style: (:), legs: (left: 1, right: 1))
beamsplitter(x, y, label: [$BS(theta, phi)$], name: none, style: (:), legs: (left: 2, right: 2))
two_mode_squeezer(x, y, label: [$S_2(z)$], name: none, style: (:), legs: (left: 2, right: 2))
cv_controlled_addition(x, y, label: [$CX(s)$], name: none, style: (:), legs: (left: 2, right: 2))
cv_controlled_phase(x, y, label: [$CZ(s)$], name: none, style: (:), legs: (left: 2, right: 2))
cubic_phase(x, y, label: [$V(gamma)$], name: none, style: (:), legs: (left: 1, right: 1))
kerr(x, y, label: [$K(kappa)$], name: none, style: (:), legs: (left: 1, right: 1))
cross_kerr(x, y, label: [$CK(kappa)$], name: none, style: (:), legs: (left: 2, right: 2))
homodyne(x, y, label: [$x$], name: none, style: (:), legs: (left: 1, right: 1))
heterodyne(x, y, label: [$alpha$], name: none, style: (:), legs: (left: 1, right: 1))
photon_number_measurement(x, y, label: [$n$], name: none, style: (:), legs: (left: 1, right: 1))
vacuum(x, y, label: [$0$], name: none, style: (:), legs: (right: 1))
fock_state(x, y, label: [$n$], name: none, style: (:), legs: (right: 1))These are convenience constructors exported by @preview/typograph-circuit:0.1.0. controlled_z aliases cz; fredkin aliases cswap. Marker size: is a non-negative length or auto. auto leaves normal theme/diagram/instance min-size precedence intact; filled and open controls default to 5pt, and the target defaults to 12pt. An explicit size replaces that styled minimum; a label may still enlarge the fitted marker. cnot forwards its control-size: and target-size: values to the corresponding marker.
typ.port(node, side, index: 0)side is "left"/"right"/"top"/"bottom"; index may be positional. Resolved once the node’s measured outline is known; carries its node, so an edge or relative placement through a port alone still draws the gate. node can also be a named ref("gate"); that gate must be emitted elsewhere, and its port capability/index are checked during layout. The result exposes deferred .x and .y values and is accepted as a single node position.
Index zero is the bottommost left/right port, or the leftmost top/bottom port. Omitted sides have no ports. port-spacing spaces candidates on the bounding rectangle, then projects them onto the actual silhouette; exact spacing is not guaranteed after projection onto curved or undersized shapes. size: overrides a gate’s minimum, not its label-plus-inset fit.
typ.offset(point, dx, dy)Returns a point shifted by numeric diagram units. Signed/zero offsets and nested offsets are accepted; lengths and rel() sources are not. The result exposes .x/.y, captures direct source nodes, and works in node constructors, place, and edge waypoints. An offset moves a node’s center, not its boundary. Use offset(p, 1, 0).x, not arithmetic on deferred p.x.
typ.node-type(kind, base-style: (:), flippable: false)Returns (x, y, label: none, name: none, style: (:)), or, with flippable: true, (x, y, label: none, flip: auto, name: none, style: (:)). Both variants also accept a single point in place of x, y. kind must be a string. See Directional shapes and flip for when to set flippable: true.
typ.make-node(kind, x, y, label: none, name: none, style: (:), base-style: (:), size-scale: 1, ..extra)Low-level escape hatch node-type is built on; extra fields can’t replace reserved item fields. Prefer node-type unless a constructor genuinely needs extra metadata node-type doesn’t expose.
15.2 Style keys
typ.node-defaults // ==
(
shape: typ.shapes.empty,
shape-labelled: auto,
fill: none,
stroke: none,
min-width: 0pt,
min-height: 0pt,
inset: 0pt,
radius: 0pt,
rotate: 0deg,
flip: false,
slant: 0.55,
tip: 0.32,
font-size: auto,
)| Key | Contract |
|---|---|
shape |
Builder function. See Shape Reference. |
shape-labelled |
Alternate builder used only when a label is present, or auto. |
fill, stroke |
Native Typst paint/stroke values. |
min-width, min-height, min-size |
min-size shorthand expands both axes; an explicit per-axis key wins on its axis within one dictionary regardless of write order; across dictionaries, later always wins on whichever axis it sets. |
inset |
Number/length, or side dictionary (left/right/top/bottom/x/y/rest); unknown side keys error. A number is points at the reference scale (unlike diagram margins, where numbers are coordinate units). Both forms follow node zoom. |
radius |
Uniform corner radius for rect/square: length, percentage, or relative length; clamped to the maximum sensible rounded radius. No per-corner radii. |
rotate |
Angle, Typst screen convention (+90deg visually clockwise). Rejected (not ignored) by axis-aligned builders when nonzero. |
flip |
Boolean; mirrors a directional builder across its local y-axis, before rotate. |
slant |
Consumed by trapezoid. |
tip |
Consumed by arrow. |
font-size |
auto, or a length overriding this node’s label size. |
Node style dictionaries are open: unknown keys pass through to a custom shape builder unchanged, rather than erroring. Compare Edge style keys, which are closed.
15.3 Precedence
typ.node-defaults
-> constructor base-style
-> selected theme's preset for node.kind
-> diagram(node-styles: (kind: (...)))
-> node(style: (...)), and direct box()/gate() arguments
A theme’s own node constructor table — like typograph-zx’s — lives in that theme’s own reference, not here: this page only covers the generic constructors every theme is built from.