4 Extending
zx.theme is ordinary data, so a project theme extends it exactly the way typograph’s own Theming chapter describes: shallow, explicit composition with +, never by mutating this package’s values.
#import "@preview/typograph:0.1.0" as typ
#import "@preview/typograph-zx:0.1.0" as zx
#let pentagon = typ.node-type("pentagon")
#let node-presets = zx.theme.node-presets + (
z: zx.theme.node-presets.z + (
fill: rgb("#c7e9ff"),
stroke: 0.8pt + navy,
),
pentagon: (
shape: typ.shapes.regular(vertices: 5, rotate: -90deg),
fill: rgb("#f2e8ff"),
stroke: 0.8pt + purple,
min-size: 13pt,
inset: 3pt,
),
)
#let edge-presets = zx.theme.edge-presets + (
ghost: (stroke: (paint: gray, dash: "dashed")),
)
#let ghost = typ.edge-type("ghost")
#let my-theme = typ.theme(
palette: zx.theme.palette,
node-presets: node-presets,
edge-defaults: zx.theme.edge-defaults,
edge-presets: edge-presets,
)#import "@preview/typograph:0.1.0" as typ
#let diagram = typ.diagram.with(theme: my-theme)
#diagram(scale: 1.1cm, {
let p = pentagon(0, 0, label: [P])
let q = zx.z(1.4, 0, label: $alpha$)
ghost(p, q)
})classic.node-presets.z + (fill: ..) keeps z’s existing shape, shape-labelled, min-size, and inset and only overrides fill/ stroke. Writing z: (fill: blue) instead would replace the whole preset, discarding those other fields — a theme never guesses which fields you meant to keep.
pentagon and ghost are brand new kinds, declared with the exact same node-type()/edge-type() factories z/plain themselves are built from — see Constructors. There is no separate mechanism for “this theme’s own kinds” versus “a project’s added kinds.”