Visualization

A definition you can read is a definition you can trust. Crucible renders any machine to two diagram formats with one method call each.
Two renderers
Section titled “Two renderers”mermaid := m.ToMermaid() // GitHub-renderable stateDiagram-v2dot := m.ToDOT() // GraphViz DOT, for richer SVG outputToMermaid produces a stateDiagram-v2 that renders inline on GitHub and in
docs. ToDOT emits GraphViz DOT, better for large, deeply hierarchical
machines where Mermaid grows unreadable, and for high-fidelity SVG on slides and
docs sites. Both are deterministic: states keep their declared order, edges are
sorted, so repeated calls are byte-identical and golden-stable.
Both renderers express the full structure: compound states nest, parallel regions render with dividers (Mermaid) or dashed clusters (DOT), final states draw their terminal marker, and owned states color-code by owner.
Options
Section titled “Options”The same variadic options tune either format:
m.ToMermaid(state.WithoutGuards()) // drop the [guard] suffixesm.ToMermaid(state.WithoutOwners()) // drop owner color-codingm.ToMermaid(state.LeftToRight()) // direction LRm.ToDOT(state.TopToBottom()) // rankdir=TBSame graph, code or JSON
Section titled “Same graph, code or JSON”Rendering is a pure function of the machine graph, the very structure the IR
carries. A machine loaded with LoadFromJSON
and re-quenched renders identically to one forged in code:
ir, _ := state.LoadFromJSON[Stage, Signal, Order](b)m := ir.Provide(reg).Quench()fmt.Println(m.ToMermaid()) // same diagram, byte for byteA real diagram
Section titled “A real diagram”The diagram below is generated at build time from fooddelivery.NewModel() via
ToMermaid(), the same machine the example’s tests exercise, so it can never
drift from the code:
stateDiagram-v2
[*] --> Placed
state Active {
[*] --> Active_Fulfillment__Cooking
Active_Fulfillment__Cooking
Active_Fulfillment__AwaitingCourier
Active_Fulfillment__EnRoute
Active_Fulfillment__AwaitingCourier --> Active_Fulfillment__EnRoute: PickedUp
Active_Fulfillment__Cooking --> Active_Fulfillment__AwaitingCourier: PlatedUp
--
[*] --> Active_Watchdog__OnTime
Active_Watchdog__OnTime
Active_Watchdog__Overdue
Active_Watchdog__Overdue --> [*]
Active_Watchdog__OnTime --> Active_Watchdog__Overdue: after(30m0s) SLABreached
}
Delivered --> [*]
Canceled --> [*]
Rejected --> [*]
Active --> Refunding: Cancel
Active --> Settling: DroppedOff
Authorizing --> Active: Authorized [or(generousOrder,and(subtotal ge 5000,priority in ["fast","express"]))]
Authorizing --> Rejected: Declined
Placed --> Authorizing: Submit
Refunding --> Canceled: Refunded
Settling --> Delivered
These renderers power this very docs site: every embedded statechart is forged from a live machine, never hand-drawn. For the full lifecycle walkthrough behind the diagram, see the food-delivery example.