The block grammar
A content file is optional YAML front matter, then blocks. A block is a run of lines between an opening ::: kind line and a closing ::: line. Blocks nest one level deep. The format has ten blocks and one fenced language, plot.
The ten blocks
| Block | Id | Sits in | Holds | Is |
|---|---|---|---|---|
::: card | none | a deck | Markdown | one step of the deck |
::: figure | optional | a deck | Markdown | a picture with a caption, as a card |
::: flashcard | optional | a deck | Markdown, answer, solution | a practice item, after the cards or between two |
::: question | optional | a checkpoint | Markdown, answer, solution | a question of an exam |
::: answer | none | a flashcard, a question | Markdown | the back of the flashcard, or the answer to the question |
::: solution | none | a flashcard, a question | Markdown | the full working |
::: reference | required | a deck | # Title, Markdown, equation, legend, derivation | a result to look up |
::: equation | none | a reference | plain LaTeX | the bare equation |
::: legend | none | a reference | $symbol$: meaning rows | what each symbol means |
::: derivation | none | a reference | Markdown | why the reference holds |
An index.md holds no blocks. Its front matter is all that counts, and text after the front matter is an error.
Each block has its own page: Decks and cards for card and figure, Flashcards and solutions for flashcard, answer and solution, Exams for question, and References and derivations for reference, equation, legend and derivation.
The syntax
Front matter
The front matter starts on the first line of the file, with a line that holds only ---. It ends at the next line that holds only ---. Between the two lines, write YAML.
---
title: Ohm's law
---
A file without a first --- line has no front matter. A file whose front matter never closes has no front matter either: the parser reads the whole file as body.
An opening line
An opening line starts with :::, then the kind of the block, then an optional id:
::: flashcard q1
- Spaces before
:::and between the words have no effect. - The id is the first word after the kind. Further words have no effect.
- The compiler reads the id of a
flashcard, aquestion, afigureand areference. It ignores a word after any other block. - An id is one word: it contains no space.
A closing line
A closing line holds ::: and nothing else. It closes the block that opened last.
Nesting
A block inside another block opens and closes inside it. Close the inner block first. Blocks nest one level only: a block inside a block cannot hold a third block.
::: flashcard q1
Solve $3x - 6 = 9$ for $x$.
::: answer
$x = 5$.
:::
::: solution
$$ 3x - 6 = 9 \implies 3x = 15 \implies x = 5 $$ ∎
:::
:::
The last ::: closes the flashcard. Indentation is optional. You can indent the inner blocks for clarity, but do not indent Markdown by four spaces or more: Markdown reads such lines as code.
Fenced code
Inside a fenced code block, a ::: line is content, not a marker. A fence opens with three or more backticks or tildes, and it closes on a line that starts with the same run. So a card can show the format itself:
::: card
A card opens like this:
```markdown
::: card
One idea.
:::
```
:::
A fence with the language plot is a live plot (Live plots). Any other fence shows as code.
Where each block can sit
Five blocks can stand at the top level of a file: card, figure, flashcard, question and reference. The other five always sit inside a parent.
| File | Top-level blocks |
|---|---|
| a deck | card, figure, flashcard, reference |
| a checkpoint | question |
an index.md | none |
| Parent | Children |
|---|---|
flashcard, question | answer, solution |
reference | equation, legend, derivation |
| any other block | none |
The faults
The checker reports a fault in the grammar with its file and its line.
| Fault | Message |
|---|---|
| a word that is not a block | ERROR ./math/alg/linears/solving.md:23: `lesson` is not a block: the grammar is card, figure, flashcard, question, answer, solution, reference, equation, legend, derivation |
| a block that never closes | ERROR ./math/alg/linears/solving.md:23: block `card` is never closed: add a `:::` line |
a ::: that closes nothing | ERROR ./math/alg/linears/solving.md:23: `:::` closes nothing here |
| a block two levels deep | ERROR ./math/alg/linears/solving.md:27: `::: card` opens two blocks deep, and a block nests one level at most (an `answer` in a `flashcard`, a `legend` in a `reference`): close the block above it first |
| a child block at the top level | ERROR ./math/alg/linears/solving.md:23: `answer` cannot sit on its own: it belongs inside the block it explains |
| a block in the wrong parent | ERROR ./math/alg/linears/solving.md:24: `answer` cannot sit inside `card` |
| a block in the wrong file | ERROR ./math/alg/linears/index.md:5: `card` cannot sit inside `topic` |
| text outside a block in a deck | ERROR ./math/alg/linears/solving.md:5: this text sits outside any block, so the app never shows it: put it in a `::: card`, or take it out |
text after the front matter of an index.md | ERROR ./math/alg/linears/index.md:7: this text sits outside any block, so the app never shows it: an `index.md` holds front matter and nothing else: take it out |
| a flashcard without an answer | ERROR ./math/alg/linears/solving.md:9: this block has no `::: answer`: a flashcard needs its back, and a question its answer |
| the block of format 2 | ERROR ./math/alg/linears/solving.md:9: `exercise` is not a block since format 3: write `flashcard` in a deck and `question` in a checkpoint |
| two flashcards with one id | ERROR ./math/alg/linears/solving.md:13: `q1` is already the id of another flashcard in this file, at line 5: rename one |
| two figures with one id | ERROR ./math/alg/linears/solving.md:9: `f` is already the id of another figure in this file, at line 5: rename one |
The first four faults stop the parse of the file. The file does not load. If it is the only child of its parent, the checker also reports the parent as empty:
ERROR ./math/alg/linears/index.md: this topic holds nothing: give it children, or take it out
Fix the first fault, and the second one goes too.
Markdown in a block
A block that holds Markdown takes CommonMark, with math:
| Works | Written |
|---|---|
| paragraphs | a blank line between them |
| emphasis | *italic*, **bold** |
| inline code | `code` |
| lists | - item, 1. item |
| quotes | > text |
| headings | ## Heading |
| code | a fenced block |
| inline math | $a x + b = 0$ |
| display math | $$ x = 3 $$ |
| pictures |  |
| links | [label](reference:id), [label](figure:id), [label](https://…) |
These do not work:
- Tables. A pipe table shows as plain text with its
|characters. - Strikethrough and footnotes. The marks show as plain text.
- Raw HTML. The app shows an HTML tag as the text it is. A
<b>in a card shows as<b>. - Remote pictures. A picture must come from an
assets/directory of the repository.
A deck with every block
---
title: What a field is
---
::: card
The most familiar field is gravity. The Earth fills the space around it with a gravitational
field, and any mass placed in that field feels a pull ([Figure](figure:gravity-field)).
:::
::: figure gravity-field

Earth's gravitational field reaches every point of the surrounding space.
:::
::: card
Near the surface, the pull on a mass is its weight.[Weight](reference:weight)
```plot
x: { var: m, label: "$m$ in kg", from: 0, to: 10, ticks: 2, grid: true }
y: { label: "$W$ in N", from: 0, to: 100 }
draw:
- curve: { is: 9.81 * m, accent: true }
```
:::
::: flashcard q1
What is the weight of a 2 kg mass near the surface of the Earth?
::: answer
About 19.6 N. Multiply the mass by $g$.
:::
::: solution
$W = m g = 2 \times 9.81 = 19.62$ N. ∎
:::
:::
::: reference weight
# Weight
The weight of a mass near the surface of the Earth.
::: equation
W = m g
:::
::: legend
$W$: weight, in newtons
$m$: mass, in kilograms
$g$: gravitational field strength, about 9.81 N/kg
:::
::: derivation
The field strength $g$ is the force on each kilogram, so a mass $m$ feels $m$ times that force. ∎
:::
:::