Mathup

Easy MathML authoring tool with a quick to write syntax.

Installation

npm
npm install mathup
import mathup from "mathup";
Client

Download one of the following:

…and include the module:

<script type="module" src="mathup.js"></script>

…the custom element:

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

…or the script:

<script src="mathup.iife.js"></script>

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
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 ex of 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-associative and 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 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 represent them as operators like so:

\]{: a, b :}\[
Additional fences
{: 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 assignmet you can write:

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

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:

: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
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
bg.black
Black
bg.gray
Gray
bg.lightgray
Lightgray
bg.white
White