The diagrams config option (added in symfony-carve 0.1.2) turns selected
fenced blocks into hydration elements for a client-side renderer, instead of plain code
blocks. All eight built-in presets are enabled in config/packages/carve.yaml:
carve:
safe_mode: true
raw_html: strip
diagrams: ['mermaid', 'plantuml', 'graphviz', 'd2', 'vega_lite', 'wavedrom', 'chart', 'abc']
The injected CarveRenderer service on this page uses exactly that config, so
a ``` mermaid fence becomes <pre class="mermaid">...</pre>,
a ``` vega-lite fence becomes <div class="vega-lite"><script type="application/json">...,
and so on. The bundle only emits the markup - you supply the browser library that draws it.
Every card below shows the Carve source, the emitted markup, and the live drawn result.
Note on spelling: the config enum value is vega_lite (underscore),
while the fence word authors type is vega-lite (hyphen).
<pre><code class="language-mermaid">flowchart LR
A[Write Carve] --> B{diagrams enabled?}
B -->|yes| C[hydration element]
B -->|no| D[plain code block]
</code></pre>
<pre class="mermaid" role="img" aria-label="mermaid">flowchart LR
A[Write Carve] --> B{diagrams enabled?}
B -->|yes| C[hydration element]
B -->|no| D[plain code block]</pre>
Rendered live by mermaid.js. The library loads from a CDN and draws entirely in the browser.
Renderer: mermaid.js (CDN, client-side)
``` mermaid
flowchart LR
A[Write Carve] --> B{diagrams enabled?}
B -->|yes| C[hydration element]
B -->|no| D[plain code block]
```
<pre class="mermaid" role="img" aria-label="mermaid">flowchart LR
A[Write Carve] --> B{diagrams enabled?}
B -->|yes| C[hydration element]
B -->|no| D[plain code block]</pre>
flowchart LR
A[Write Carve] --> B{diagrams enabled?}
B -->|yes| C[hydration element]
B -->|no| D[plain code block]
The dot source is rendered to SVG fully in-browser by the @viz-js/viz WebAssembly build. No server call.
Renderer: @viz-js/viz WebAssembly (CDN, offline after load)
``` dot
digraph {
rankdir=LR;
Carve -> HTML -> Diagram;
}
```
<pre class="graphviz" role="img" aria-label="graphviz">digraph {
rankdir=LR;
Carve -> HTML -> Diagram;
}</pre>
digraph {
rankdir=LR;
Carve -> HTML -> Diagram;
}
D2 has no small in-browser build, so the source is deflate-encoded and drawn through the public Kroki server. If the network is blocked the source stays visible.
Renderer: Kroki server (public kroki.io, needs network)
``` d2
Carve -> HTML: convert
HTML -> Diagram: hydrate
```
<pre class="d2" role="img" aria-label="d2">Carve -> HTML: convert
HTML -> Diagram: hydrate</pre>
Carve -> HTML: convert HTML -> Diagram: hydrate
The source is hex-encoded and drawn by the public PlantUML server via its ~h scheme. If the network is blocked the source stays visible.
Renderer: plantuml.com server (~h hex encoding, needs network)
``` plantuml
@startuml
Alice -> Bob: config option
Bob --> Alice: hydration markup
@enduml
```
<pre class="plantuml" role="img" aria-label="plantuml">@startuml
Alice -> Bob: config option
Bob --> Alice: hydration markup
@enduml</pre>
@startuml Alice -> Bob: config option Bob --> Alice: hydration markup @enduml
A Vega-Lite JSON spec rides in a <script type="application/json"> and is drawn by vega-embed. Note the fence word is vega-lite (hyphen); the config enum spells it vega_lite.
Renderer: vega + vega-lite + vega-embed (CDN, client-side)
``` vega-lite
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {"values": [
{"engine": "PHP", "tier": 3},
{"engine": "JS", "tier": 3},
{"engine": "Rust", "tier": 3}
]},
"mark": "bar",
"encoding": {
"x": {"field": "engine", "type": "nominal"},
"y": {"field": "tier", "type": "quantitative"}
}
}
```
<div class="vega-lite" role="img" aria-label="vega-lite"><script type="application/json">{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {"values": [
{"engine": "PHP", "tier": 3},
{"engine": "JS", "tier": 3},
{"engine": "Rust", "tier": 3}
]},
"mark": "bar",
"encoding": {
"x": {"field": "engine", "type": "nominal"},
"y": {"field": "tier", "type": "quantitative"}
}
}</script></div>
A WaveDrom JSON timing spec, drawn to SVG by the wavedrom library.
Renderer: wavedrom + default skin (CDN, client-side)
``` wavedrom
{ "signal": [
{ "name": "clk", "wave": "p......" },
{ "name": "data", "wave": "x.34.5x", "data": ["a", "b", "c"] }
]}
```
<pre class="wavedrom" role="img" aria-label="wavedrom">{ "signal": [
{ "name": "clk", "wave": "p......" },
{ "name": "data", "wave": "x.34.5x", "data": ["a", "b", "c"] }
]}</pre>
{ "signal": [
{ "name": "clk", "wave": "p......" },
{ "name": "data", "wave": "x.34.5x", "data": ["a", "b", "c"] }
]}
A Chart.js JSON config in a <script type="application/json">, drawn onto a <canvas> by chart.js.
Renderer: chart.js (CDN, client-side)
``` chart
{
"type": "bar",
"data": {
"labels": ["PHP", "JS", "Rust"],
"datasets": [{ "label": "Carve engines", "data": [3, 3, 3] }]
},
"options": { "responsive": true }
}
```
<div class="chart" role="img" aria-label="chart"><script type="application/json">{
"type": "bar",
"data": {
"labels": ["PHP", "JS", "Rust"],
"datasets": [{ "label": "Carve engines", "data": [3, 3, 3] }]
},
"options": { "responsive": true }
}</script></div>
ABC music notation rendered to a score (SVG) by abcjs.
Renderer: abcjs (CDN, client-side)
``` abc
X:1
T:Carve Scale
M:4/4
L:1/4
K:C
C D E F | G A B c |
```
<pre class="abc" role="img" aria-label="abc">X:1
T:Carve Scale
M:4/4
L:1/4
K:C
C D E F | G A B c |</pre>
X:1 T:Carve Scale M:4/4 L:1/4 K:C C D E F | G A B c |
Each preset needs its own browser library on the page. The bundle stays renderer-agnostic; this page wires one renderer per type from public CDNs:
@viz-js/viz WebAssembly build (renders offline once loaded).<canvas>.~h
hex scheme (needs network).Every renderer degrades gracefully: if a library or server is unreachable, the diagram source stays visible as text rather than vanishing.