@cristianormazabal/triton-latex
v0.1.29
Published
LaTeX integration for Triton — render diagrams to vector PDF for \includegraphics.
Maintainers
Readme
@triton/latex — Triton diagrams in LaTeX
Author Triton diagrams inline in your .tex file — write the diagram source
between \begin{triton} … \end{triton} and it renders to a vector PDF at
compile time, dropped in exactly like a tikzpicture. No pre-render step, no
figure files to manage.
\usepackage{triton}
\begin{triton}
flowchart LR
A[Start] --> B{Choice}
B -->|yes| C[Ship it]
B -->|no| D[Fix it]
D --> E[Review]
\end{triton}Compile with shell-escape:
tectonic -Z shell-escape -Z shell-escape-cwd=. mydoc.tex
pdflatex -shell-escape mydoc.tex
lualatex -shell-escape mydoc.texFor environments where shell-escape is off (e.g. Overleaf), the same package
also supports a precompile + \includegraphics workflow — see
Overleaf / no-shell-escape fallback.
How inline rendering works
When LaTeX hits \begin{triton}, the package:
- Captures the body verbatim (via
fancyvrb'sVerbatimOut) to a temp file,\jobname.triton-src.triton— brackets, indentation and all. - Content-hashes that file with
\pdf@filemdfivesum(frompdftexcmds). - Shells out (
\write18) to the Triton CLI to render it to\jobname.triton-cache/<hash>.pdf— but only if that PDF doesn't already exist, so unchanged diagrams are not re-rendered on subsequent runs. \includegraphicsthe resulting vector PDF.
The render is pure-JS, no system binaries (no Inkscape, rsvg-convert, or
Chromium). Text becomes real vector glyphs in the embedded base-14 fonts
(Helvetica/Times/Courier), so there is no font-drift between dev, CI, and the PDF.
If shell-escape is off or the CLI is missing, the environment fails with a
clear \PackageError telling you exactly what to fix — it never silently emits a
blank.
Setup
cd latex
pnpm install # pdfkit + svg-to-pdfkit (isolated from core triton)
node esbuild.mjs # → dist/cli.cjs (runs build:grammars first)This builds the triton-latex CLI. Point the package at it once with
\tritoncli (or put triton-latex on PATH and skip this — it's the default):
\tritoncli{node /abs/path/to/latex/dist/cli.cjs}Per-diagram sizing
A verbatim environment cannot carry an inline optional argument — peeking for
a [ on the \begin{triton} line tokenises the line break that fancyvrb needs
to find the end of that line, which swallows the diagram's first line. (minted
sidesteps this only because of its mandatory {language} argument.) So
\begin{triton}[width=…] is not supported.
Instead, set the \includegraphics options for the next diagram just before
it, or change the default globally:
\tritonnext{width=0.55\linewidth} % applies to the NEXT \begin{triton} only
\begin{triton}
flowchart TD
P[Parse] --> L[Layout] --> R[Render]
\end{triton}
\tritonsetup{width=0.8\linewidth} % new global default for all later diagramsOne-liners
For a single line of source, \tritoninline takes a verbatim argument delimited
by any character (here |) and an optional \includegraphics key list:
\tritoninline[width=3cm]|flowchart LR; A --> B|Macro reference
| Macro | Effect |
| --- | --- |
| \begin{triton} … \end{triton} | Inline authoring → render → include (needs shell-escape). |
| \tritonnext{<opts>} | \includegraphics options for the next inline diagram only. |
| \tritoninline[<opts>]\|…\| | One-line inline source (verbatim, any delimiter). |
| \tritonsetup{<opts>} | Default \includegraphics options (default width=\linewidth). |
| \tritoncli{<cmd>} | CLI invocation (default triton-latex). |
| \tritontheme{<name>} | Theme preset passed to the CLI for inline renders. |
| \tritonthemefile{<path>} | Load an external .triton-theme.json by file path. |
| \tritonthemesdir{<dir>} | Scan a directory for *.triton-theme.json files. |
| \tritonscale{<n>} | Scale passed to the CLI (default 1). |
| \tritoncachedir{<dir>} | Render cache directory (default \jobname.triton-cache). |
| \triton[<opts>]{<name>} | Precompile fallback: \includegraphics of <dir>/<name>.pdf. |
| \tritonfile[<opts>]{<name>} | Explicit alias of the precompile include form. |
| \tritonfig[<opts>]{<name>}{<caption>} | Precompile include wrapped in a captioned figure. |
| \tritondir{<path>} | Directory holding precompiled <name>.pdf (default triton-figures). |
Depends only on graphicx, fancyvrb, and pdftexcmds — engine-agnostic
(pdfLaTeX / XeLaTeX / LuaLaTeX / tectonic).
Example
examples/inline-demo.tex authors two diagrams inline
and renders them at compile time. From examples/:
tectonic -Z shell-escape -Z shell-escape-cwd=. inline-demo.tex
triton.stydiscovery:tectoniconly searches the input file's own directory for local.styfiles (it ignoresTEXINPUTS).examples/triton.styis therefore a symlink to../triton.sty. With a real package install (orpdflatex, which honoursTEXINPUTS) the symlink is unnecessary.
CLI
The same CLI powers both the inline environment and manual/precompile rendering:
# one file → vector PDF
node dist/cli.cjs render diagram.mmd -o figures/diagram.pdf
# one file → SVG pass-through (convenience)
node dist/cli.cjs render diagram.mmd -o diagram.svg
# whole directory of *.triton / *.mmd → <name>.pdf
node dist/cli.cjs render-dir diagrams/ -o figures/
# options
node dist/cli.cjs render diagram.mmd -o out.pdf --theme executive --scale 2Installed as the triton-latex bin when the package is linked.
External themes
Use a .triton-theme.json file to apply a custom colour palette and typography
to every inline diagram in your document.
.sty macros
\tritonthemefile{.triton/themes/my-brand.triton-theme.json}
% — OR —
\tritonthemesdir{.triton/themes} % scan a directory, then use \tritontheme{name}\tritonthemefile{<path>} passes --theme-file <path> to the CLI for every
inline \begin{triton} render in the document. \tritonthemesdir{<dir>} passes
--themes-dir <dir>; combine it with \tritontheme{<name>} to select a theme by
name from the discovered registry.
CLI flags
# Load a specific theme file
node dist/cli.cjs render diagram.mmd -o out.pdf \
--theme-file .triton/themes/my-brand.triton-theme.json
# Scan a directory and select by name
node dist/cli.cjs render diagram.mmd -o out.pdf \
--themes-dir .triton/themes --theme my-brand⚠️ Cache caveat
The cache key includes the theme-file path, not its content. After editing
a .triton-theme.json in place, clear the cache before recompiling:
latexmk -C # preferred
rm -r <jobname>.triton-cache # or manuallySee docs/external-themes.md for the full format reference, field list, built-in preset names, and cross-host worked example.
Overleaf / no-shell-escape fallback
Overleaf (and any compile with shell-escape disabled) can't run the CLI, so render the diagrams to PDF ahead of time and include the committed assets:
\usepackage{triton}
\tritondir{figures}
\triton{flowchart} % \includegraphics figures/flowchart.pdf
\tritonfig[width=0.6\linewidth]{avl}{An AVL tree.}cd examples
make figures # render diagrams/ → figures/ (vector PDF)
make pdf # compile demo.tex (tectonic or pdflatex)Workflow:
- Render locally:
make figures(orrender-dir). - Commit
figures/*.pdf,triton.sty, and your.tex. - Upload to Overleaf — it compiles with no Node, no Triton, no shell-escape.
Regenerate the PDFs whenever a diagram source changes. Because the bare
\triton{<name>} command and the triton environment share a name, the package
dispatches on context (\@currenvir): \begin{triton} authors inline, while
\triton{<name>} includes a precompiled PDF.
Why a separate package
This is an isolated satellite package (its own node_modules,
pnpm-workspace.yaml, and lockfile), exactly like extension/. The PDF toolchain
(pdfkit, svg-to-pdfkit) lives here and only here — the core triton
package gains zero new dependencies. The CLI imports the compiler by relative
path from ../src and esbuild bundles it in.
