formulaa 0.1.0

WYSIWYG TUI math editor rendering Unicode/ASCII-art formulas
Documentation

formulAA

ci

Math as plain text you can actually edit. Three pieces:

  • a 2D text format for formulas โ€” Unicode "ASCII art" with a formal grammar (docs/aa-spec.md): every picture has exactly one reading and parses back to the syntax tree it was rendered from;
  • a WYSIWYG structure editor in the terminal for writing it;
  • converters to and from LaTeX, and a formatter.

Typing the quadratic formula in the editor, saving it, converting it to LaTeX, and reopening it to change a sign

$ formulaa gauss.aa              # edit it in the terminal; ^W writes and quits
$ cat gauss.aa                   # the file is just the picture
 โˆž    -๐‘ฅยฒ   โ”Œโ”€
โ”ˆโˆซโ”ˆโ”ˆ ๐‘’   ๐‘‘๐‘ฅ=โˆšฯ€
 -โˆž
$ formulaa --aa2latex gauss.aa   # the picture converts to LaTeX
\int_{-\infty }^{\infty }e^{-x^{2}}dx=\sqrt{\pi }
$ formulaa --aa2latex gauss.aa | formulaa --latex2aa   # and converts back
 โˆž    -๐‘ฅยฒ   โ”Œโ”€
โ”ˆโˆซโ”ˆโ”ˆ ๐‘’   ๐‘‘๐‘ฅ=โˆšฯ€
 -โˆž

There is no separate source file behind the picture: the AA text is what gets stored, edited and converted. Put it anywhere plain text goes.

Why a picture as the source

Terminals, git, Markdown and prompts all work on plain text, but math fits it badly. LaTeX is machine-readable, but a human has to picture \frac{-b\pm\sqrt{b^2-4ac}}{2a} in their head. ASCII art is readable at a glance, but no program can interpret it.

Diagram tools take the drawing itself as the source and render it from there โ€” ditaa (2004), aafigure, ASCIIToSVG, Markdeep (2015), svgbob, GoAT. formulAA does the same for math, with LaTeX as the output instead of SVG.

One picture, one reading

Those tools interpret free-form drawings as best they can. That works for boxes and arrows, but not for math: a above b could be a fraction, a limit, or two unrelated lines, and a wrong guess silently changes the meaning.

So formulAA does not interpret arbitrary drawings. It defines a format (docs/aa-spec.md) in which every accepted picture has exactly one reading; the rules are summarized in what makes a picture parseable below.

This requires a few reserved structural glyphs โ€” the fraction bar โ”€, the operator band โ”ˆ, delimiter columns โŽ› โŽœ โŽ, grid junctions โ”ผ โ€” which never appear as ordinary content and have to line up correctly. Keeping them aligned by hand would be tedious, so the editor does it: it edits the syntax tree and redraws the picture. The files themselves are still plain text โ€” you can edit them in vim, paste them into a document, or have a language model write them (SKILL.md documents the format for that purpose).

The editor

formulaa formula.aa opens the editor on a file; ^O saves and ^W saves and quits. Full reference: keys ยท commands.

  • Type naturally: letters become math italics, // makes a fraction, ^/_ open scripts, ( [ { auto-size, and a \ minibuffer with Tab completion covers the rest (\frac, \sum, \alpha, \bbR, aliases like \-> and \oo).
  • Arrows move through structure; โ†‘/โ†“ enter limits. Shift+โ†/โ†’ selects, and a structure key wraps the selection.

Three modes help once a formula grows past one line.

^F โ€” the free cursor

Arrows move over the picture instead of through the tree; Enter lands on the nearest edit position.

Correcting entries of a Vandermonde determinant

^B โ€” block select

^B highlights the enclosing structures of the cursor, โ†‘/โ†“ widen and narrow the selection, so a whole subexpression can be copied in a few keys.

Building the DPO loss by copying the policy ratio

^G โ€” grid edit

Inside a matrix, ^G gives a cell cursor; c and r switch to column and row lanes, where Enter on a gap inserts one and Backspace on a lane removes it.

Growing a 2x2 rotation matrix into a 3x3 one

The core idea: what makes a picture parseable

The format is designed around four rules that make parsing deterministic:

  1. Every subexpression owns a rectangle and a baseline row. Siblings sit in disjoint column ranges; vertical structure exists only inside a rectangle. Parsing is: find the baseline, scan left to right, recurse into the rectangles that structural glyphs claim.

  2. Structure is drawn with glyphs that can never be atoms. The bar โ”€, the band โ”ˆ, delimiter columns โŽ› โŽœ โŽ, the radical โˆš are banned from ordinary content, so when one appears it always marks structure. Atoms come from an allow-list of one-cell characters, so a wide or combining character cannot break the grid.

  3. Extent is spanned, never counted. A bar is wider than both its arguments; a band sandwiches its operator. No rule depends on how many spaces separate two things, so shifting something sideways while hand-editing does not change the reading.

  4. One canonical spelling per tree. The renderer's output is the normal form and the parser accepts a superset. What the picture cannot distinguish, the AST does not represent: accents stack as flat lists, because the picture cannot tell \hat{\underline{x}} from \underline{\hat{x}}.

The result is that a formula is a picture and a syntax tree at the same time.

Examples

Taken from the test corpus (more examples); each parses back to its exact tree and converts to the LaTeX shown.

The quadratic formula:

      โ”Œโ”€โ”€โ”€โ”€โ”€โ”€
   -๐‘ยฑโˆš๐‘ยฒ-4๐‘Ž๐‘
๐‘ฅ=โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
       2๐‘Ž
x=\frac{-b\pm \sqrt{b^{2}-4ac}}{2a}

Cauchyโ€“Schwarz:

โŽ›  ๐‘›     _ โŽž    โŽ›  ๐‘›      โŽž โŽ›  ๐‘›      โŽž
โŽœโ”ˆโ”ˆโˆ‘โ”ˆโ”ˆ ๐‘ขโ‚–๐‘ฃโ‚–โŽŸยฒ โ‰ค โŽœโ”ˆโ”ˆโˆ‘โ”ˆโ”ˆ ๐‘ขโ‚–ยฒโŽŸ โŽœโ”ˆโ”ˆโˆ‘โ”ˆโ”ˆ ๐‘ฃโ‚–ยฒโŽŸ
โŽ ๐‘˜=1      โŽ     โŽ ๐‘˜=1     โŽ  โŽ ๐‘˜=1     โŽ 
\left(\sum_{k=1}^{n}u_{k}\bar{v}_{k}\right)^{2}\le \left(\sum_{k=1}^{n}u_{k}^{2}\right)\left(\sum_{k=1}^{n}v_{k}^{2}\right)

A Vandermonde determinant โ€” grids carry explicit lattice markers, so rows and columns stay unambiguous even with empty cells:

โŽก 1   ๐‘ฅโ‚   ๐‘ฅโ‚ยฒ   โ‹ฏ   ๐‘ฅโ‚โฟโปยน โŽค
โŽข   โ”ผ    โ”ผ     โ”ผ   โ”ผ       โŽฅ
โŽข 1   ๐‘ฅโ‚‚   ๐‘ฅโ‚‚ยฒ   โ‹ฏ   ๐‘ฅโ‚‚โฟโปยน โŽฅ
โŽข   โ”ผ    โ”ผ     โ”ผ   โ”ผ       โŽฅ = โ”ˆโ”ˆโ”ˆโ”ˆโˆโ”ˆโ”ˆโ”ˆโ”ˆ (๐‘ฅโฑผ-๐‘ฅแตข)
โŽข โ‹ฎ   โ‹ฎ     โ‹ฎ    โ‹ฑ     โ‹ฎ   โŽฅ    1โ‰ค๐‘–<๐‘—โ‰ค๐‘›
โŽข   โ”ผ    โ”ผ     โ”ผ   โ”ผ       โŽฅ
โŽฃ 1   ๐‘ฅโ‚™   ๐‘ฅโ‚™ยฒ   โ‹ฏ   ๐‘ฅโ‚™โฟโปยน โŽฆ

CLI

formulaa formula.aa            # edit a formula file (^O saves, ^W saves and quits,
                               #   ^Y copies the AA; a missing file is created)
cat formula.aa | formulaa -    # โ€ฆor take it from stdin
formulaa --aa2latex formula.aa # AA โ†’ LaTeX (stdin works too)
formulaa --latex2aa formula.tex # LaTeX โ†’ AA, best effort (KaTeX/MathJax dialect)
formulaa --format formula.aa   # normalize hand-written AA to canonical form

Everything --aa2latex emits reads back to the same tree, and \latex in the editor opens a box to paste LaTeX into (unknown commands are skipped, never an error).

Fonts

The format leans on Unicode math symbols โ€” mathematical alphanumerics (๐‘ฅ, ๐’Ÿ, ๐”ผ), big operators, bracket pieces, box drawing โ€” which most coding fonts cover only in part. JuliaMono has all of them at a monospace width and is the recommended font for the editor; tools/merge_math_font.py ports just those glyphs into another coding font if you would rather keep yours.

For AI agents

Language models can read and write the format directly. SKILL.md is a self-contained guide for them, including the verification loop (--format to check the syntax, --aa2latex to confirm the meaning). This makes AA a practical way to embed re-editable math in documents that humans and agents both maintain.

MIT licensed.