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
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
if
or
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
cosh
cot
csc
det
dim
gcd
lcm
ln
log
max
min
mod
sec
sin
sinh
tan
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:
Where 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 and the denominator
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
⇒
), the ascii caret will impose a superscript (a^2
⇒
), 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
.
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 and 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
, while e^ -1 / 2
yields
.
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)||
|~x~|
|__x__|
Additional fenced shortcuts
binom(a, b)
abs x
norm x
ceil x
floor 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 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
and the -th root of respectively.
Accents
The following commands will add accents over or under the following expression or add other types of highlighting:
Accents
hat a
bar a
vec a
dot a
ddot a
tilde a
ul a
oparen a+b
uparen a+b
obrace a+b
ubrace a+b
obracket a+b
ubracket a+b
oshell a+b
ushell a+b
cancel 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
bf
it
bf it
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
orange
yellow
green
cyan
blue
purple
black
gray
lightgray
white
Backgrounds
bg.red
bg.orange
bg.yellow
bg.green
bg.cyan
bg.blue
bg.purple
bg.black
bg.gray
bg.lightgray
bg.white