Diagram Generation on FreeBSD 15 with Emacs Org-Mode
Table of Contents
1. Environment
| Component | Version |
|---|---|
| OS | FreeBSD 15.0-RELEASE amd64 |
| Emacs | 31.0.50 (via poetry run emacs) |
| Org-mode | 9.7.11 |
| Node | 24.12.0 |
| Chromium | 143.0.7499.192 |
| ob-mermaid | installed, batch-disabled (see below) |
2. Test results (2026-04-18)
All tests run in emacs --batch with org-babel-execute-buffer,
matching the publish pipeline (gmake publish).
| Backend | Tool path | Version | Batch exec | Tangle | Publish |
|---|---|---|---|---|---|
| dot | /usr/local/bin/dot | 14.1.1 | yes | yes | yes |
| neato | /usr/local/bin/neato | 14.1.1 | yes | yes | yes |
| fdp | /usr/local/bin/fdp | 14.1.1 | yes | yes | yes |
| sfdp | /usr/local/bin/sfdp | 14.1.1 | untested | - | - |
| twopi | /usr/local/bin/twopi | 14.1.1 | untested | - | - |
| circo | /usr/local/bin/circo | 14.1.1 | untested | - | - |
| mermaid (npx) | npx @mermaid-js/mmdc | 11.12.0 | yes (slow) | yes | no |
| mermaid (mmdc) | /usr/local/bin/mmdc | broken | no | - | - |
| ditaa | /usr/local/bin/ditaa | - | no | - | - |
| gnuplot | /usr/local/bin/gnuplot | 5.4p10 | no | - | - |
| plantuml | /usr/local/bin/plantuml | - | no | - | - |
2.1. Failure modes
- mermaid (mmdc):
/usr/local/bin/mmdcis a broken symlink (dangling reference to a removednode_modulespath). Works vianpxwithPUPPETEER_EXECUTABLE_PATH=/usr/local/bin/chromeandPUPPETEER_SKIP_DOWNLOAD=1, butnpxis slow (~5s per diagram) and unreliable for batch publish.ob-mermaidis configured inproject-config.elfor interactive use (C-c C-c) but not batch. - ditaa: requires AWT (Java GUI subsystem). GraalVM JDK 21 on this
host is missing
libXext.so.6. Would work with OpenJDK + X11 libs installed. - gnuplot:
ob-gnuplotfails silently in batch. Likely a terminal configuration issue (set terminal pngbeforeset output). - plantuml: same AWT dependency as ditaa (both are Java). Broken
until
libXextis installed.
2.2. Hypothesis invalidated
The project-config.el comment "FreeBSD lacks puppeteer support"
(added ~2025) was partially wrong. FreeBSD 15 has Chromium 143
installed. Puppeteer works at runtime when told to use system
Chromium via PUPPETEER_EXECUTABLE_PATH. The failure is in
puppeteer's postinstall script, which tries to download a
Chromium binary (no FreeBSD build exists). Fix:
PUPPETEER_SKIP_DOWNLOAD=1 npm install -g @mermaid-js/mermaid-cli.
The practical decision: use graphviz for all diagrams in the publish pipeline. Mermaid is available for interactive use but not reliable for batch. The graphviz suite (dot, neato, fdp, sfdp, twopi, circo) is native, fast, and fully supported.
3. The reliable path: dot in org-babel
3.1. Minimal example
digraph G {
rankdir=LR;
node [shape=box, style="rounded,filled", fillcolor="#f5f5f5"];
A [label="Source"];
B [label="Process"];
C [label="Output"];
A -> B -> C;
}
This block:
- Renders inline when you press
C-c C-cin Emacs. - Generates
diagram-test-dot.pngin the same directory as the org file. - Embeds the image in the exported HTML when
gmake publishruns. - No manual steps. No pre-committed PNGs. No Makefile target.
3.2. With tangle (editable .dot source alongside)
digraph G {
rankdir=TB;
node [shape=box];
"org file" -> "C-c C-v t" -> ".dot file";
"org file" -> "C-c C-c" -> ".png file";
"org file" -> "gmake publish" -> ".html + .png";
}
:tangle writes the .dot source to disk when you invoke
C-c C-v t. Useful when you want to edit the diagram with a
graphviz-specific tool (xdot, dot -Tx11, an IDE plugin).
3.3. Choosing a layout engine
All graphviz engines use the same DOT language but different layout algorithms:
| Engine | Best for | :cmd value |
|---|---|---|
dot |
Directed graphs, hierarchies, flows | dot |
neato |
Undirected, spring-model (small) | neato |
fdp |
Undirected, spring-model (large) | fdp |
sfdp |
Very large undirected (scalable fdp) | sfdp |
twopi |
Radial layouts | twopi |
circo |
Circular layouts | circo |
Usage:
graph G {
A -- B -- C -- D -- A;
A -- C;
B -- D;
}
3.4. Output formats
:file extension determines format: .png, .svg, .pdf.
SVG is preferable for web (scalable, smaller), but org-publish's
wal.sh-research-images component handles all three:
:base-extension "png\\|jpg\\|gif\\|svg\\|pdf\\|pptx"
4. The 55-mermaid migration path
This repo has 55 #+begin_src mermaid blocks across 20+ org files.
None currently generate PNGs during batch publish.
4.1. Decision
Convert mermaid → dot where the diagram matters for the published site. Leave mermaid blocks as-is where they're purely notes (never published, or published as code blocks rather than images).
4.2. Conversion patterns
| Mermaid type | Graphviz equivalent |
|---|---|
flowchart |
digraph (directed) or graph (undirected) |
sequenceDiagram |
Not natural in dot; use numbered edges |
stateDiagram |
digraph with state-shaped nodes |
classDiagram |
digraph with record nodes |
erDiagram |
digraph with record nodes + crow's-foot hack |
gantt |
No good equivalent; keep as mermaid or text |
pie |
No equivalent; keep as mermaid or text |
Most of the 55 blocks are flowcharts and sequence diagrams. Flowcharts convert directly; sequence diagrams approximate with numbered edges (as in the egress-proxy diagram).
5. Related
- Cloudflare Agents Week 2026 — four graphviz diagrams demonstrating the approach in practice.
- Claude Code Workshop —
:eval no-exportpattern for runnable but safe blocks.
