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/mmdc is a broken symlink (dangling reference to a removed node_modules path). Works via npx with PUPPETEER_EXECUTABLE_PATH=/usr/local/bin/chrome and PUPPETEER_SKIP_DOWNLOAD=1, but npx is slow (~5s per diagram) and unreliable for batch publish. ob-mermaid is configured in project-config.el for 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-gnuplot fails silently in batch. Likely a terminal configuration issue (set terminal png before set output).
  • plantuml: same AWT dependency as ditaa (both are Java). Broken until libXext is 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;
}

diagram-test-dot.png

This block:

  • Renders inline when you press C-c C-c in Emacs.
  • Generates diagram-test-dot.png in the same directory as the org file.
  • Embeds the image in the exported HTML when gmake publish runs.
  • 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";
}

diagram-test-tangle.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;
}

diagram-test-neato.png

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

Author: Jason Walsh

j@wal.sh

Last Updated: 2026-04-18 18:14:32

build: 2026-04-18 23:18 | sha: 86f4ea8