Math, figures and assets

Math

Write math in LaTeX, between dollar signs. The import turns it into MathML, and the browser draws the MathML in the math font of the theme. The learner can select it like text.

WrittenGives
$a x + b = 0$inline math, in the line of text
$$ x = 3 $$display math, on a line of its own
\$5a literal dollar sign

Rules for inline math:

  • Put no space after the opening $ and no space before the closing $. $ x $ stays plain text.
  • Write a dollar of money as \$.

Display math can sit in its own paragraph, or in a line of text. Both give display math.

Several lines

A line break \\ works only inside an environment. For a chain of steps, use aligned:

$$
\begin{aligned}
3x - 6 &= 9 \\
3x &= 15 \\
x &= 5
\end{aligned}
$$

A \\ in display math outside an environment is a fault.

What works

These commands work. The list is not complete, but it covers what a course needs:

KindCommands
fractions and roots\frac{a}{b}, \dfrac{a}{b}, \sqrt{x}, \sqrt[3]{x}, \binom{n}{k}
scriptsx^2, x_i, x_{i+1}^{2}
big operators\sum_{i=1}^{n}, \prod, \int_0^1, \iint, \oint, \lim_{x \to 0}, \bigcup
accents\vec{v}, \hat{n}, \bar{x}, \dot{x}, \ddot{x}, \tilde{x}, \overline{AB}, \overrightarrow{AB}, \widehat{x}
text and fonts\text{m/s}, \mathrm{d}x, \mathbf{F}, \mathit{x}, \mathsf{x}, \mathtt{x}, \mathbb{R}, \mathcal{L}, \mathfrak{g}, \boldsymbol{x}
functions\sin, \ln, \exp, \log_2, \det, \max, \operatorname{sgn}
delimiters\left( \frac{a}{b} \right), \langle x \rangle, \lfloor x \rfloor, \bigl( \bigr)
environmentspmatrix, bmatrix, vmatrix, matrix, array, cases, aligned, align
arrows and relations\to, \implies, \iff, \mapsto, \xrightarrow{f}, \le, \ge, \ne, \approx, \equiv, \propto
symbolsGreek letters, \infty, \partial, \nabla, \hbar, \ell, \pm, \times, \cdot, \circ, \degree
layout\underbrace{a+b}_{n}, \overset{!}{=}, \quad, \,, \;, \hspace{1em}

What does not work

WrittenWrite instead
\newcommand, or any macro of your ownthe full command each time
\textbf{…}, \textit{…}, \mbox{…}\mathbf{…}, \mathit{…}, \text{…}
\frac12, an argument without braces\frac{1}{2}
\tag, \labelnothing: equations have no numbers
\boxed, \phantom, \vphantomnothing
\ce{…} (chemistry), \SI{…} (units)\text{H}_2\text{O}, 3\ \text{m}
\color{…}nothing: it parses, but math always takes the ink of the page

LaTeX that does not parse is an error. The renderer would draw a red box in place of the math, so the checker and the import refuse it. The message names the file, the line, the LaTeX and the first parse error (Check your repository):

ERROR ./math/alg/linears/solving.md:6: the LaTeX `\frac{a}` will not render: parsing error: expected a token

The checker reads all math: the prose, the ::: equation blocks, and the symbols and the meanings of the legends. Math that nests deeper than 256 levels is an error too.

Math in other places

  • The ::: equation block of a reference holds plain LaTeX with no dollar signs (References and derivations).
  • The symbol of a ::: legend row is math: $I$: current, in amperes.
  • The labels of a plot take $math$, with limits (Live plots).

Assets

An asset is a picture that a card shows. It lives in an assets/ directory.

RuleDetail
wherein an assets/ directory beside any index.md: the root, a domain, a section, a topic or a checkpoint folder. An assets/ directory can hold subdirectories.
types.png, .jpg, .jpeg, .webp, .svg
size256 KB at most per file (262,144 bytes)

A picture file outside an assets/ directory, a file of another type in one, and a file over the cap are faults:

ERROR ./math/alg/linears/pic.png: `pic.png` sits outside an `assets/` directory: every asset belongs in one
ERROR ./math/alg/linears/assets/notes.txt: `notes.txt` is not an asset this format carries: use .png, .jpg, .jpeg, .webp or .svg
ERROR ./math/alg/linears/assets/big.png: `big.png` is 300000 bytes, over the 262144-byte cap: shrink it before committing it

Use a picture

Write a Markdown image. The text in the brackets is the name of the picture for a screen reader:

![A voltage divider: two resistors in series, the output tapped between them](assets/divider.svg)

The path is relative to the file that uses it, as in any Markdown tool. It can climb with ../, so a deck can use a picture of its section:

![The circuit symbols](../assets/symbols.svg)

The checker reads each path, and the file it names, at the line that uses it:

FaultMessage
no such filemath/alg/linears/solving.md:6: `assets/none.png` is not in this repository
a path that leaves the repositorymath/alg/linears/solving.md:6: `../../../../../a.png` leaves the repository
a picture on another sitemath/alg/linears/solving.md:8: `https://example.com/a.png` is a link to another site, and a card fetches nothing: commit the picture under `assets/`

The checker reads the content of a picture only when a block uses it. It does not read the content of a picture that nothing uses, but it checks the type and the size of every file in an assets/ directory.

The app fetches nothing when a learner reads. So the import puts each picture into the card that uses it. A raster picture becomes a data: address, which is a third larger than the file. A picture used in three cards is in the compiled domain three times. A domain compiles to 32 MB of HTML at most, pictures included, and the checker refuses a domain past this cap. Keep pictures small, and prefer SVG.

SVG figures

An SVG becomes part of the page, so it follows the light and the dark theme. The import does not copy your file. It reads it, keeps the elements and the attributes it knows, and writes a new SVG from them. Everything else goes, silently.

Elements that stay

svg, g, defs, title, desc, path, line, polyline, polygon, rect, circle, ellipse, text, tspan, marker, clipPath, linearGradient, stop.

Any other element goes, with everything inside it. This includes script, style, image, use, symbol, a, foreignObject, pattern, radialGradient, mask, filter, textPath and every animation. A shape inside a <a> or a <symbol> goes with it. Comments, the XML declaration and the doctype go too.

The first element must be <svg>. Everything after the end of that root element goes.

Attributes that stay

KindAttributesAllowed values
namesidletters, digits, -, _
geometryviewBox, preserveAspectRatio, width, height, x, y, x1, y1, x2, y2, cx, cy, r, rx, ry, dx, dy, d, points, transform, gradientTransform, offset, markerWidth, markerHeight, refX, refYnumbers, letters, spaces, ., ,, -, +, (, ), %
paintfill, stroke, stop-colornone, currentColor, #rgb, #rrggbb, #rrggbbaa, var(--token), url(#id)
opacity and strokeopacity, fill-opacity, stroke-opacity, stop-opacity, stroke-width, stroke-dasharray, stroke-dashoffset, stroke-miterlimitas geometry
wordsfill-rule, stroke-linecap, stroke-linejoin, clipPathUnits, orientone word, 32 characters at most
referencesclip-path, marker-start, marker-mid, marker-endnone or url(#id)
type, on text, tspan, title and desc onlyfont-size, letter-spacing as geometry; font-style, font-weight, text-anchor, dominant-baseline, baseline-shift, paint-order as words

Any other attribute goes, and so does a value that breaks its rule. Note these:

  • style goes. Write each property as its own attribute: stroke-width="2", not style="stroke-width:2".
  • class goes, because a class names the styles of the app.
  • The width and the height of the root <svg> go. The root takes its size from the card and its shape from its viewBox.
  • Each id takes a prefix from a hash of the file, and each url(#…) takes the same prefix. So an id in a figure never matches an id of the page or of another figure.
  • font-family goes. The text takes the font of the page.
  • href and xlink:href go.
  • A colour name or rgb() goes. fill="red" goes, and the shape then takes the default fill of SVG, which is black. Write colours as hex.
  • A value longer than 8,192 characters goes. A long d of a path then goes, and the path draws nothing. Split a long path into several paths.

An editor such as Inkscape writes many attributes of its own. They go, and the drawing stays if it uses only the attributes above. Export as plain SVG, and check the result in the app.

Theme colours

Three exact colours follow the theme:

WriteBecomesIs
#000000currentColorthe ink of the page
#1a1a1avar(--graph-ink)the ink of a graph
#0000ffvar(--graph-blue)the accent colour

Write them with six digits. #000 is not #000000 here. Any other colour stays as you wrote it, in both themes, so it can vanish on a dark page. Draw in #000000, and use #0000ff for the one thing that needs an accent.

Size

The app draws an SVG at the width of the card, up to 40rem, centred. The height follows the viewBox, so give each SVG a viewBox. A root without a viewBox takes one from its width and its height when both are plain numbers. Lines keep one stroke width at every size.

Faults

The checker and the import repair a missing end tag without a message. They refuse these, at the line that uses the SVG:

ERROR ./math/alg/linears/solving.md:10: `math/alg/linears/assets/a.svg`: this file holds no <svg> element
ERROR ./math/alg/linears/solving.md:10: `math/alg/linears/assets/a.svg`: this SVG nests deeper than 32 levels: flatten it
ERROR ./math/alg/linears/solving.md:10: `math/alg/linears/assets/a.svg`: this SVG holds more than 20000 elements: simplify it

An example

This is part of gravity-field.svg from Stemin Foundations. It uses only kept elements and attributes, and the ink colour:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 361 259" fill="none" stroke="#000000" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
  <title>Earth's field reaching the Moon</title>
  <circle cx="129.6" cy="129.6" r="34.0" fill="none" stroke="#000000"/>
  <text x="129.6" y="134.1" text-anchor="middle" font-size="12" font-style="normal">Earth</text>
  <line x1="197.6" y1="129.6" x2="184.5" y2="129.6" stroke="#000000"/>
  <path d="M175.5 129.6 L184.5 126.0 L184.5 133.2 Z" fill="#000000" stroke="none"/>
</svg>

Raster pictures

A .png, .jpg, .jpeg or .webp file shows as an image, at its own size, and 40rem wide at most. It does not follow the theme. Use a raster picture for a photograph, and SVG for a drawing.