Mathup

mathup.xyz · 2026-07-14 · by Long Nguyen ·generic

Mathup

#### Installation

##### npm

npm install mathup
import mathup from "mathup";

##### Client

Download one of the following:

  • Module (full, min)
  • Script (full, min)
  • Custom element as module (full, min)
  • Custom element as script (full, min)
  • Stylesheet (full; not needed for custom element)

…and include the module:

<script type="module" src="mathup.js"></script>
<link rel="stylesheet" href="mathup.css" />

…the custom element:

<script type="module" src="math-up-element.js"></script>

…or the script:

<script src="mathup.iife.js"></script>
<link rel="stylesheet" href="mathup.css" />

#### Usage

const expression = "1+1 = 2";
const options = {};  // optional
const mathml = mathup(expression, options);

mathml.toString(); // => "<math><mrow><mn>1</mn><mo>+</mo><mn>1</mn></mrow><mo>=</mo><mn>2</mn></math>"

const mathNode = mathml.toDOM(); // => [object MathMLElement]

// Update existing <math> node in place mathup("3-2 = 1", { bare: true }).updateDOM(mathNode);

##### Custom Element

<math-up
  display="inline"
  dir="ltr"
  decimal-mark=","
  col-sep=";"
  row-sep=";;"
>
  1+1 = 2
</math-up>

##### Command line

npm install -g mathup
mathup [options] -- <expression>

or from stdin

echo <expression> | mathup [options]

#### Options (with defaults)

const options = {
  decimalMark: ".",   // -m  --decimal-mark="."
  colSep: ",",        // -c  --col-sep=","
  rowSep: ";",        // -r  --row-sep=";"
  display: "inline",  // -d  --display="inline"
  dir: "ltr",         //     --rtl
  bare: false,        // -b  --bare
};

Note: If you pick `,` as your decimal mark then `;` becomes the new default column separator. And if `;` is your column separator then the new default row separator becomes `;;`. You can use `,` as both a decimal mark and a row separator if you take care to add a space between the row separator and the following digit. However then you must set both explicitly.

const options = {
  decimalMark: ",",
  colSep: ",",
};

Quick to write / Easy to read

This package exposes a single function `mathup`that intuitively takes simple mathematical expressions—written in a markup language inspired by AsciiMath—and outputs structured MathML.

You can use it on the command line or on the server as a node package, or in the browser by including the script source. In the browser, you choose how to parse the math in your document—by looking hard for any math-y substrings, parsing all expressions wrapped in `$`…`$`, or using some other excellent tools out there that does it for you. And you can choose what to do with the output as well—piping it to another program, inject it streight to the DOM, or just logging it to the console.

Why not just use MathJax?

MathJax is an excellent tool that you can safely use if all you want to do is include complex mathematical expressions in a document. However, MathJax is a complex piece of software that does a great deal more than just translate simple expression into structured form, and if that is all you want to do, then MathJax is definitely overkill. Mathup promises to be a lot faster (by doing less) then MathJax. While MathJax will search for expressions, parse them, translate, and render them. Mathup only parses and translates them, and lets the browser do the rendering.

Why AsciiMath / Why not TeΧ?

I wrote this tool, because I wanted to be able to author mathematical expressions quickly, with no overhead (imagine `1/2` instead of `\frac{1}{2}`). TeΧ expressions can easily become verbose and annoying to write (especially on keyboards with complex access to the \\, {, and } keys). However, the purpose of this package is not to give people complete control over MathML in a non-verbose way, the purpose is to make it simple for people to write simple expression. Of course I’ll try to give as much expressive power as possible in the way, but I won’t promise to make all complex things possible.

If you want full support of MathML, and don’t want to write all those tags perhaps you should look for another tool. There are other great efforts to enable people to author MathML in TeX format, take a look at TeXZilla for example.

Reference

Basics

Mathup uses four of MathML’s token elements (identifiers `<mi>`, operators `<mo>`, numbers `<mn>` and text `<mtext>`). Mathup recognizes which of these you mean when you write simple expressions.

For example: `1+1 = 2` ⇒

<mrow>
  <mn>1</mn>
  <mo>+</mo>
  <mn>1</mn>
</mrow>
<mo>=</mo>
<mn>2</mn>

And `sin theta` ⇒

<mi>sin</mi><mi>θ</mi>

Mathup will also recognize most of the unicode characters you’ll write. If a character comes from one of the mathematical operator code blocks it will wrap it in an `<mo>` tag, otherwise it will be wrapped in an `<mi>` tag. Additionally `d` will be wrapped in an `<mo>` tag if it obviously a part of a differential.

Numbers

Numbers are usually what you think they are (including unicode numerals like Ⅻ or ↋). However if you want to write a number in an odd way (like spelling it out, as a hex string, or as a roman numeral) you can prepend a string with `#`, (e.g. `#0x2A`) or—if your number includes a non alphanumeric character—prepend a backticked fence (like in markdown) `` #` ``…`` ` ``like so: `` #`forty two` `` or ``` #`` `42 `` ``` to make `` `42 `` a number.

Operators

Anything in the `Pc`, `Pd`, `Pe`, `Pf`, `Pi`, `Po`, `Ps`, `Sm`, or `So` unicode categories is considered an operator. Additionally the symbol character or alphanumeric string immediately following a backslash `\` will become an operator (`<mo>`). If you need more then one symbol character, or more then one word, as a single operator in the operator (e.g. `<mo>for each</mo>`), you can fence it following markdown semantics; (e.g. `` \`for each` `` or ``` \`` ` `` ``` for `` <mo>`</mo> ``).

The following will also map to the respective operator.

Operational `.$` `FUNCTION APPLICATION`(zero width) `.` `INVISIBLE TIMES`(zero width) `.+` `INVISIBLE PLUS`(zero width) `lim`lim `mod`mod `-`− `+-`± `-+`∓ ``· `xx`× `-:`÷ `//`⁄ `prod`∏ `sum`∑ ``∗ `@`∘ `^^`∧ `vv`∨ `nn`∩ `uu`∪ `int`∫ `dint`∬ `oint`∮ `!=`≠ `!==`≢ `o+`⊕ `ox`⊗ `o.`⊙ `^^^`⋀ `vvv`⋁ `nnn`⋂ `uuu`⋃ `*`⋆ `|><|`⋈ `|><`⋉ `><|`⋊ Miscellaneous `'`′ `''`″ `'''`‴ `''''`⁗ `aleph`ℵ `del`∂ `grad`∇ `oc`, `prop`∝ `/`∠ `/\`△ `||`∥ `~=`≅ `~~`≈ `sub`⊂ `sup`⊃ `sube`⊆ `supe`⊇ `<>`, `diamond`⋄ `[]`, `square`□ `<|`⊲ `|>`⊳ Relational `in`∈ `!in`∉ `-=`, `==`≡ `<=`≤ `>=`≥ `-<`≺ `>-`≻ `-<=`⪯ `>-=`⪰ `<<<`≪ `>>>`≫ Logical `and`and `if`if `or`or `otherwise`otherwise `not`¬ `AA`∀ `EE`∃ `|--`⊢ `TT`⊤ `|`⊥ `|==`⊨ Arrows `<-`, `larr`← `uarr`↑ `->`, `rarr`→ `darr`↓ `harr`↔ `->>`↠ `>->`↣ `|->`↦ `lArr`⇐ `=>`, `rArr`⇒ `<=>`, `iff`, `hArr`⇔ `>->>`⤖ Punctuations `.,` `INVISIBLE SEPARATOR`(zero width) `...`… `:.`∴ `vdots`⋮ `cdots`⋯ `ddots`⋱

Identifiers

Anything not a number, operator, or text is considered an identifier. This includes latin, greek or arabic letters (`A`, `π`, `ح`) or even emoji. Each character is considered a separate identifier unless they spell out a word found in the tables below or the operator table above.

You can force any sequence of characters to be a single idendifier by surrounding them in fences (e.g. `` `Gamma` `` yields `<mi>Gamma</mi>` and ``` `` f` `` ``` yields `` <mi>f`</mi> ``)

The following will also produce a single identifier:

Standard functions `cos`cos `cosh`cosh `cot`cot `csc`csc `cosec`cosec `det`det `dim`dim `gcd`gcd `lcm`lcm `ln`ln `log`log `max`max `min`min `mod`mod `sec`sec `sin`sin `sinh`sinh `tan`tan `tanh`tanh Greek `Delta`Δ `Gamma`Γ `Lambda`Λ `Omega`Ω `Phi`Φ `Pi`Π `Psi`Ψ `Sigma`Σ `Theta`Θ `Xi`Ξ `alpha`α `beta`β `chi`χ `epsilon`ɛ `eta`η `gamma`γ `kappa`κ `lambda`λ `mu`μ `nu`ν `omega`ω `phi`φ `phiv`ϕ `pi`π `psi`ψ `rho`ρ `sigma`σ `tau`τ `theta`θ `upsilon`υ `xi`ξ `zeta`ζ Additional identifiers `oo`∞ `O/`∅ `CC`ℂ `NN`ℕ `QQ`ℚ `RR`ℝ `ZZ`ℤ

Text

You can surround anything in double quotes (`"some text"`) and it will get displayed as text. If your text annotation contains a quote mark you can surround it with more quotemarks (just like with backtick fences). That is `"" "text string" ""` will give you `<mtext>"text string"</mtext>`.

Spaces

MathML has an element called `<mspace>`. Two or more spaces in a row will be translated into that element where it makes sense. The width of the space will be:

"width" = { 0.35(n - 1)\\,, if n = 2 or n = 3 0.5(n - 1)\\,, if n = 4 or n = 5 n - 3\\,, if n > 5

Where n is the number of subsequent spaces and width is in units of ex which is the height of the ‘x’ character in your font.

In addition `(mod p)` will add 1.65 exof space to the left of the open parenthesis.

Fractions

In MathML you enclose fractions in an `<mfrac>` element. In Mathup you simply separate the numerator a and the denominator b with a slash (`a/b`).

Mathup tries to be smart about what you mean as numerator and denominator by looking at the spaces you surround your subexpressions with, so `a+b / c+d` is not the same thing as `a + b/c + d`. Generally a space between the subexpression and the slash will apply the entire subexpression, while no space only aplies what immediately precedes or follows.

Sub and superscripts

The underscore will impose the following expression as a subscript on the preceding expression (`a_i` ⇒ ai ), the ascii caret will impose a superscript (`a^2` ⇒ a2 ), and the (expression, underscore, caret) / (experssion, caret, underscore) sequence (`a_i^2`/`a^2_i`) will impose a sub and superscript on the first expression yielding a i 2 .

Over and underscripts follow a similar pattern exept with `.` for underscripts and `.^` for overscripts. Also `lim_x` will put _x as an underscript, and `sum_a^b` and `prod_a^b` will put a and b as under and overscripts.

Unlike fractions, sub/super and under/overscripts are right-associativeand take precedence over fractions. You can strategically place whitespace between the sub/sup, or under/over character and the surrounding sub expressions just like with fractions, e.g. `e^ -1/2` yields e − 1 2 , while `e^ -1 / 2` yields e −1 2 .

Fenced Groups

We can use parenthesis to group terms together. An any unicode open parenthesis (unicode category `Ps`) starts a fence, and any closing parenthesis (category `Pe`) closes it. Note that parenthesis don’t have to match, but they do have to come in open/close pairs.

You denote an unfenced group with `{:` and `:}`. You are free to surround the contents of the unfenced group with arbitrary operators and the will become the new fence. For example if you need an open parenthesis to close a group, you can cast them to operators and manually fence the group like so:

`\]{: a, b :}\[` ⇒ \] a,b \ .

Finally, inside groups—along with your normal seperators like `,`—you can use the special `:|:` as group separators. This is especially handy to write [bra-ket notation:

`(: Phi :|: Psi :)` ⇒ ⟨Φ|Ψ⟩.

Additional fences `{:a, b:}`a , b `(:a:|:b:)`⟨ a | b ⟩ `<<a, b>>`⟨ a , b ⟩ `|(a, b)|`| a , b | `|:a, b:|`| a , b | `||(a, b)||`∥ a , b ∥ `||:a, b:||`∥ a , b ∥ `|~x~|`⌈ x ⌉ `|_x_|`⌊ x ⌋ Additional fenced shortcuts `binom(a, b)`( a b ) `abs x`| x | `norm x`∥ x ∥ `ceil x`⌈ x ⌉ `floor x`⌊ x ⌋

Matrices

Matrices are fenced groups with at least one row separator (`;`) For example `A = [1,2,3; 4,5,6]` is a 2×3 matrix and `[1,4; 2,5; 3,6]` is A T . A trailing row break is allowed so you can write a single row matrix as `[1,2,3;]`. A new-line character can also be used as a row separator.

All this does is put the outer brackets as a fence around the table inside, so if you want case assignment you can write:

|x| = { x, if x >= 0 ; -x, otherwise :}

Tensors and Indices

To write tensors or any other complex indices you can start a group with either a hat ^ or an underscore \ character. The following expression will be your first upper or lower index respectively. Every following ^ or \ will start a new index `A(^b_c)` for A cb . If you want your index on a new column you can add a , before the ^ or \: `A(^b,_c)`A b c . You can repeat the previous index position by omitting the ^ or \ after a comma: `A(_b,c,d,^e,f,g)`A b c d e f g .

You can also add prescripts by immediately following with an expression. `[^14_6]rm C`C 614 or both `(^n)P(_k)`P k n . Prescripts take priority.

If you want to add sub- or superscripts to your indices, you can surround the entire index with parenthesis `A(^(a_i),...,(a_n))` ⇒ A ai … an . And if you want to use a comma or a parenthesis as an index, you can escape it with a backslash \\ `A(_beta, \,, \, a)`A β, \[a .

Roots

MathML has `<msqrt>` and `<mroot>` tags for roots. Mathup similarly provides `sqrt x` and `root n x` (or `root(n, x)` if you prefer) for the squared root of x and the n-th root of x respectively.

Accents

The following commands will add accents over or under the following expression or add other types of highlighting:

Accents `hat a`a^ `bar a`a‾ `vec a`a→ `dot a`a⋅ `ddot a`a⋅⋅ `tilde a`a˜ `ul a`a\_ `oparen a+b`a+b ⏜ `uparen a+b`a+b ⏝ `obrace a+b`a+b ⏞ `ubrace a+b`a+b ⏟ `obracket a+b`a+b ⎴ `ubracket a+b`a+b ⎵ `oshell a+b`a+b ⏠ `ushell a+b`a+b ⏡ `cancel a+b`a+b

Font commands

You can prefix any expression with a font command. Then all token elements in that expression will have the following variant. Some variants can be combined, order doesn’t matter.

Bold (`bf`), italic (`it`), sans-serif (`sf`), and monospace (`tt`) on texts (`bf tt "text"`) are set using CSS. If you want to control the font-family of sans-serif and monospace texts, you can set the [CSS custom properties `--mathup-font-family-sans-serif` and `--mathup-font-family-monospace`respectively.

Font Commands `rm`normal `bf`bold `it`italic `bf it`bold italic `bb`𝕕𝕠𝕦𝕓𝕝𝕖-𝕤𝕥𝕣𝕦𝕔𝕜 `cc`𝓈𝒸𝓇𝒾𝓅𝓉 `bf cc`𝓼𝓬𝓻𝓲𝓹𝓽 `fr`𝔣𝔯𝔞𝔠𝔱𝔲𝔯 `bf fr`𝖋𝖗𝖆𝖈𝖙𝖚𝖗 `sf`𝗌𝖺𝗇𝗌-𝗌𝖾𝗋𝗂𝖿 `bf sf`𝘀𝗮𝗻𝘀-𝘀𝗲𝗿𝗶𝗳 `it sf`𝘴𝘢𝘯𝘴-𝘴𝘦𝘳𝘪𝘧 `bf it sf`𝙨𝙖𝙣𝙨-𝙨𝙚𝙧𝙞𝙛 `tt`𝚖𝚘𝚗𝚘𝚜𝚙𝚊𝚌𝚎

Colors

You can change the color or background of a portion of your experssion simply by typing that color. Backgrounds are prefixed by `bg.<colorname>`. If you don’t like that color variant, you can overwrite it using the `--mathup-color-<colorname>` or `--mathup-background-<colorname>` CSS custom properties. For example:

If you have an emoji keyboard you can use the colored circle emoji (🔴🟠🟡🟢🔵🟣🟤) for color and the colored square emoji (🟥🟧🟨🟩🟦🟪🟫) for the background. Black and white circles use the medium variant (⚫⚪), and black and white square use the large variant (⬛⬜).

:root {
  --mathup-color-red: lch(50% 130 20);
  --mathup-background-green: lch(50% 132 180);
}

See below for available colors

Colors `red`, `🔴`Red `orange`, `🟠`Orange `yellow`, `🟡`Yellow `green`, `🟢`Green `cyan`Cyan `blue`, `🔵`Blue `purple`, `🟣`Purple `brown`, `🟤`Brown `black`, `⚫`Black `gray`Gray `lightgray`Lightgray `white`, `⚪`White Backgrounds `bg.red`, `🟥`Red `bg.orange`, `🟧`Orange `bg.yellow`, `🟨`Yellow `bg.green`, `🟩`Green `bg.cyan`Cyan `bg.blue`, `🟦`Blue `bg.purple`, `🟪`Purple `brown`, `🟫`Brown `bg.black`, `⬛`Black `bg.gray`Gray `bg.lightgray`Lightgray `bg.white`, `⬜`White

mathup.xyz · 20 links

Comments (0)

No comments yet