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.mjs"></script>

…the custom element:

<script type="module" src="math-up-element.mjs"></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 should probably be using if all you want to do is include complex mathematical expressions in a document. And you should probably use it along side this package as well if you want Chrome users to be able to read your expressions. 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, and if the readers of your document (or users of your app) are using a standard conforming browser, they will benefit a great bit. You will be able to translate your expression on the server before your readers even open the document, reducing any lag time to native.

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.

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
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
φ
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 element will be ( n 1 ) ex where n is the number of subsequent spaces and ex is the height of the ‘x’ character in your font.

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 parentesis 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 parentesis 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_
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.

Font Commands
rm
normal
bf
bold
it
italic
bb
double-struck
cc
script
fr
fraktur
sf
sans-serif
tt
monospace