Vinculum 2.1.0 — math-feature expansion. A wave of new notation, each rendered natively and platform-free: chemistry, commutative diagrams, Young tableaux, function plots, inference rules / proof trees, siunitx units, the physics package (Dirac notation & derivatives), and syntax trees — plus equation numbering, automatic line breaking, Presentation MathML export, and more. Every feature crosses the VDL1 seam, so it renders identically on Apple, Linux, Windows, Android, and the web. No API breaks; fully compatible with 2.0.x.
Closing the coverage gaps identified in the July 2026 gap analysis, one at a time,
each with docs + a specimen figure. Every feature is platform-free (renders
identically on all targets through the VDL1 seam).
Added
- Syntax / parse trees —
\Tree [.S [.NP … ] [.VP … ] ](qtree / tikz-qtree;\qtree
alias). A labelled root centered above its children, joined by straight edges;
[.Label child …]internal nodes, bare tokens are leaves,{…}for multi-token
labels/leaves, and labels are arbitrary math (so expression trees work too). A real
2D tidy-tree layout — subtree widths bottom-up, nodes placed top-down, edges as
stroked paths — so it renders identically on all five platforms throughVDL1with no
new primitive. NewMathNode.syntaxTree; round-trips throughtoLaTeX, speaks its
structure, exports to MathML as nested rows. The tokenizer gainsbracketVerbatimCommands
so\Tree's bracket body is captured with spaces intact. (Gap analysis — linguistics / CS.) - Physics package — Dirac notation, derivatives, brackets — the most-used
physics
macros, a transpiler to LaTeX (Physics) reusing the whole engine. Dirac notation
(\bra,\ket,\braket{ϕ}{ψ}→ ⟨ϕ|ψ⟩,\ketbra,\expval{A}{ψ}→ ⟨ψ|A|ψ⟩,
\mel{ϕ}{A}{ψ}, with aliases\ip/\op/\ev/\matrixel); derivatives (\dd{x}→ dx,
\dv{f}{x}→ df/dx,\dv[n],\pdv{f}{x}→ ∂f/∂x,\pdv{f}{x}{y}mixed); brackets
(\abs,\norm,\comm{A}{B}→ [A,B],\acomm→ {A,B},\order→ O(x)); and vector
operators (\grad,\curl,\laplacian,\Tr/\tr,\rank—\divleft as ÷). Also
fixes a latent bug:\left\|…\right\|now parses to the ‖ norm delimiter instead of
falling back to parens. (Gap analysis — quantum mechanics / vector calculus.) - Units — siunitx
\num/\ang/\si/\unit/\SI/\qty— physical
quantities and units, a transpiler to LaTeX (SIUnitx) reusing the whole engine like
mhchem.\numformats numbers (scientific notation1.5e3→ 1.5×10³, thin-space digit
grouping from five digits),\angrenders angles (45;30;15→ 45°30′15″),\si/\unit
typeset unit bodies (literalkg.m.s^{-1}or macros\kilo\gram\per\second\squared,
with./~thin spaces,/solidus,\per/\squared/\cubed, and SI prefixes/units
with µ/Ω/Å/°C upright), and\SI/\qtycombine a number and a unit. Both siunitx v2 and
v3 spellings; unknown unit macros pass through as real commands. (Gap analysis — metrology.) - Inference rules / proof trees —
\inferrule[label]{premises}{conclusion}
(aliases\infer,\prftree), the mathpartir/natural-deduction notation. Premises
(\\-separated) are centered over a horizontal bar sitting on the math axis; the
conclusion is centered below; the optional bracketed label (accepts[left=Name])
sits at the bar's right at script size. Empty premises render an axiom bar; rules
nest, so full derivation trees build up. NewMathNode.inferenceRule; round-trips
verbatim, speaks as "from …, and …, infer …", exports to MathML as a zero-numerator
<mfrac>. (Gap analysis — proof theory / PL.) - Function plots — a curated pgfplots subset:
\begin{axis}[domain=a:b, samples=n] \addplot{expr}; … \end{axis}(optionally wrapped intikzpicture).
A new arithmetic evaluator (MathExpression:+ - * / ^, unary minus, parens,
x,pi/e,sin cos tan exp ln sqrt abs …) samples each curve; the layout
auto-ranges y and draws framed axes with nice-numbered ticks, gridlines, and the
curves as stroked polylines (broken across discontinuities). NewMathNode.plot;
everything is stroked paths + glyph runs, so it renders on all five platforms via
VDL1. Full TikZ/pgfplots remains out of scope. (Gap analysis Tier 3 — the
flagship plotting feature.) - Young tableaux —
\ydiagram{4,2,1}(empty Young diagram from a partition) and
\ytableaushort{134,25,6}/\young(…)(filled tableau). A grid of bordered square
cells (stroked paths), left-aligned and stacked top-down, usable inline in an
expression. NewMathNode.youngTableau; round-trips verbatim. (Gap analysis Tier 3.) - Chemistry — mhchem
\ce{…}— chemical formulas and equations. Implemented as
a transpiler to LaTeX (MHChem.transpile), reusing the whole engine (no chemistry-
specific layout): auto-subscripts (H2O→ H₂O), groups (Ca(OH)2),^charges
(SO4^2-→ SO₄²⁻), stoichiometric coefficients (2H2), reaction arrows (->,
<-,<->,<=>equilibrium, and conditional->[\Delta]), bonds (=,#),
states ((s) (l) (g) (aq)), and hydrate dots (*). (Gap analysis Tier 2.) - Commutative diagrams —
\begin{CD} … \end{CD}(amscd): objects on a grid
joined by labelled arrows (@>a>b>,@<,@VaVbV,@A,@=/@\|equality
edges,@.). A real 2D-diagram layout — objects in a grid, arrows drawn as stroked
paths (shaft + chevron head), labels at script size — so it renders identically on
all five platforms through theVDL1wire, with no diagram-specific primitive.
NewMathNode.commutativeDiagram; round-trips verbatim. (Gap analysis Tier 2 — the
flagship diagram.) - Equation numbering & cross-references — document-scoped (like macros).
\label{key}records an equation's number;\eqref{key}→(N)and\ref{key}
→Nresolve throughout prose and math (dangling key →(?)).MathText's new
numberEquations:flag auto-numbers display equations that neither\tagnor
\notag— opt-in, so default output is unchanged.\label/\notag/\nonumber
are stripped before rendering;\tagstill places the number. New platform-free
MathNumberingengine (headless-tested). (Gap analysis Tier 1.) - Automatic line breaking —
layout(node, display:, maxWidth:)wraps an
over-wide equation across lines at TeX's break points (after a binary operator or
relation), stacking the lines baseline-aligned. Top-level only (nested subformulas
stay whole); greedy fit within the budget; unbreakable runs left intact. Fully
opt-in: withoutmaxWidththe output is byte-identical to before (zero golden
churn). The long-deferred flagship layout gap. (Gap analysis Tier 1.) - Presentation MathML export —
MathMLExporter.export(node, display:)(and
MathNode.toMathML()) serializes the parse tree to<math>…</math>:<mi>/<mn>/
<mo>by atom class,<mfrac>,<msqrt>/<mroot>,<msub>/<msup>/<msubsup>,
<mmultiscripts>(prescripts),<mtable>,<mover accent="true">,<menclose>.
XML-escaped and always well-formed (verified withXMLParser); unknown input →
<merror>. For accessibility trees, copy-as-MathML, and interop. (Gap analysis
Tier 1 — a second serializer off the tree, no rendering.) - Prescripts & multiscripts —
\prescript{sup}{sub}{base}(mathtools) and
\sideset{_l^l}{_r^r}{base}(amsmath). Scripts at all four corners of a base:
isotopes (\prescript{14}{6}{C}→ ¹⁴₆C), tensors, left indices. Pre- and
post-scripts share one pair of baseline shifts so every corner aligns; the base
keeps its own operator limits. NewMathNode.multiScriptscase; round-trips via
\sideset/\prescript. (Gap analysis Tier 0 #1.) \multicolumn{n}{align}{content}— table cells spanningncolumns with
their ownl/c/ralignment, in every grid environment (headers, titles,
merged blocks). Content overflowing the span grows its last column. New
MathNode.spannedcase; the no-span path is byte-identical, so existing matrices
are unchanged. (Gap analysis Tier 0 #2.)- Harpoon accents &
\utilde—\overrightharpoon/\overleftharpoon(stretchy
harpoons over the base) and\utilde(a wide tilde below the base, stretchy).
NewMathAccentcases with an under-accent layout branch; both round-trip exactly.
(Gap analysis Tier 0 #4.) \DeclareMathOperator&\mathchoice—\DeclareMathOperator{\name}{text}
(and the*limits form) registers a document-scoped operator that renders like
\operatorname{text}, via the existing macro processor.\mathchoice{D}{T}{S}{SS}
selects one of four branches by the current math style (newMathNode.mathChoice).
(Gap analysis Tier 0 #3.)
Fixed
- Spacing commands inside
\text/\mathrm/\operatornamenow resolve instead
of printing literally:\operatorname{arg\,max}renders "arg max" (thin space),
not "arg,max".\,\:\;\quad\qquad\map to the matching space, and
\&\%\_\#\$to their literal character. Embedded$…$math still works.