An rvmark file is just a bullet point tree in plain text. Every point is called a node.
1. Root node.
1. Child node.
1. Grandchild node.
2. Other child node.
The number in front of the node is called the ordinal. It must always be ended with a period and a space.
The remaining text is called the label.
Child nodes are created with indents. This indent can be as large or small as you want, but must be the same for all children of a node.
1. Root node.
1. Child node.
1. Grandchild node.
2. Other child node.
1. Other grandchild node.
1. Great grandchild node.
You could write rvmark this way. However, it is strongly recommended to use indents of two spaces per level.
Indents can consist of spaces or tabs, but not both in the same file.
You don't need to number nodes in the right order. Nodes are displayed in the order they're written, not in the order they're numbered.
1. Root node.
1. First shown child.
3. Second shown child.
2. Third shown child.
Nodes are numbered to give readers stable permalinks. You can shuffle nodes around and insert new nodes. People's bookmarks will still point to the same place.
Any combination of letters and numbers followed by a period can be used as an ordinal.
a. Root node.
hello. Child node.
3b1b. Grandchild node.
1337. Other child node.
Sometimes it makes sense to use different numbering systems. Do whatever feels natural. Ordinals are not displayed in the rendered document.
You don't need to use ordinals if you don't want to.
You can also use - or * to let the parser take care of it.
- Root node.
- Child node.
- Grandchild node.
- Other child node.
For the purpose of permalinks, they will be assigned the first available integer.
It's better to number explicitly, not doing so means you lose permalink stability.
Implicit numbering can be used in combination with explicit numbering.
A node without an indent is called a root node. You can have as many root nodes in an rvmark file as you want, but only the first root node is displayed by the renderer.
1. Displayed by the renderer.
a. Also displayed.
2. Not displayed.
Effectively, the first root node is the document entry point, and the other root nodes are additional data meant to be transcluded. (More on this later.)
Labels are written in Markdown (CommonMark). In the standard implementation of rvmark, Markdown is rendered with Marked.js.
If you continue writing on the next line of the document without using an ordinal or bullet character, this is taken to be a continuation line of the label, and appended to the label with a space.
(Tip: Placing two spaces at the end of a label line forces a line-break. Useful for writing multi-line labels!)
Dollar signs can be used to create mathematical expressions written in KaTeX. $\sqrt{x^2}$renders as \sqrt{x^2}.
To fully understand how to write a node, there are two last elements you need to be familiar with:
1. {flag; key: value} [Tag] [Other tag] Label text.
{flag; key: value} is called the attribute block.
[Tag] [Other tag] are called the tags.
Attributes can dramatically change the appearance and functionality of a node. They are separated by semicolons ;.
Some attributes take a value, others are stand-alone flags.
Attribute blocks may also contain other elements called declarations. You'll learn about these coming up.
Tags are by default purely visual, but can be configured to also change the appearance and functionality of a node.
Tags always come at the beginning of a node after the attribute block.
The entire fun of rvmark is that you can transclude tree sections from one place to another.
1. {#root} Root node.
1. Child node.
2. {=> #other-child}
2. {#other-child} Other child node.
1. {=> #root}
2. Whoa, I'm a sibling of my own grandfather.
{#other-child} is an ID declaration setting the ID #other-child for that node.
{=> #other-child} is a transclusion declaration placing the node with ID #other-child in its location
IDs are defined in the attribute block using a declaration starting with #. You must only set one ID per node.
They are scoped to the rvmark document. You are free to reuse them across different documents within the same site.
Permalinks will always be relative to the nearest ancestor with an ID. In the previous example, "1. Child node." would receive permalink #root.1. This is the canonical address of this node.
With the {=> #id} declaration, you transclude another part of the tree wherever you like.
Transclusions can be recursive. Technically this makes the tree a directed graph. Since the tree is lazy-expanded, recursion does not cause infinite regress.
Transclusions will normally copy attributes and tags from the transcluded node.
If the transclusion also has tags, these will be prepended to those of the transcluded node. If the transclusion has an attribute, this will override the one found on the transcluded node.
If the transclusion has content, this will replace that of the transcluded node, and tags and attributes will not be copied.
Children of transclusions are dropped.
Occasionally it's useful to transclude the children of multiple nodes into one. This can be done using the multiple-transclusion syntax.
1. {=> #a, *, #b} Parent.
1. Second child.
2. {#a}
1. First child.
3. {#b}
1. Third child.
If instead of one node address, you enter a comma-separated list of multiple addresses, the children of these nodes get concatenated in the listed order.
The children of the node itself can be accessed using an asterisk *.
Transcluding a multiple-transclusion by address will transclude the calculated children. Naturally, a multiple-transclusion cannot transclude itself. Infinite regress is prevented by the renderer through cycle detection.
Multiple-transclusion will always drop the labels, attributes, and tags of the transcluded nodes. (It wouldn't be clear which ones to copy.)
Listbox nodes solve a basic problem: How can you put links to other nodes inside text? The solution is to, rather than links, have selectable options that switch out the children below the node. Try it yourself.
1. This is a [listbox]{=> #first-option} with multiple [options]{=> #second-option}.
2. {#first-option}
1. You've selected the word "listbox".
3. {#second-option}
1. You've selected the word "option".
The direct children of a listbox node are shown when no option is selected. The node is thus, in effect, always open.
| Key-value pair | Meaning |
|---|---|
draft | Node is excluded from the built website by default. |
| |
open: true | Node is expanded by default. |
| |
open: always | Node is permanently expanded. |
| |
open: never | Node is permanently collapsed. |
| |
open: false | Default (collapsed, openable). Explicit form; useful to override a tag default. |
action: link | Enter/→ focuses the first hyperlink in the node. |
| |
action: exhibit | Enter/click opens an exhibit panel. |
| |
action: none | Disables Enter/Space activation. Click to select still works. |
bullet: value | Overrides the bullet character of the node. |
bullet-alt: value | Text alternative for the bullet. |
| |
bullet-font: value | Sets the css font-family of the bullet. |
exhibit: value | Displays iframe with address value in exhibit. |
| |
| Sigil use | Meaning |
|---|---|
#value | Sets the ID of a node to be value. |
=> value | Transcludes value in the place of the node. |
= value | Sets the node-type to be value. |
.value | Sets value to be a CSS class for the node content. |
&key=value | Declares state variable key to have value value. |
?condition | Sets node visible only as long as condition is true. |
| Key-value pair | Meaning |
|---|---|
id: value | Sets ID. Alias for #value. |
transclude: value | Transcludes. Alias for => value. |
type: value | Sets node-type. Alias for = value. |
class: value | Adds CSS classes to node content element. Alias for .value. |
| Namespace token | Meaning |
|---|---|
meta.* | Sets node metadata. |
At the start of an rvmark document, you can define attributes for tags.
[Tag name {attribute; another-attribute}]
[Another tag {yet-another-attribute}]
These definitions come before the first node of the document.
The node.* attribute namespace allows you to add an attribute to every node a tag is applied to. For example, the definition [Exclamation {node.bullet: !}] would give every node with the [Exclamation] tag ! for its bullet.
| Flag | Meaning |
|---|---|
internal | Tag chip is not displayed. |
| |
| Key-value pair | Meaning |
|---|---|
color: value | Sets the --tag-color CSS variable on the tag chip, changing its color. |
label: value | Sets the display text on the tag chip. (defaults to tag name) |
tip: value | Sets the tool tip (title attribute) on the tag chip. |
href: value | Makes the tag a hyperlink. |
class: value | Adds CSS classes to the .node-content div of nodes it's applied to. Alias for .value. |
| Token use | Meaning |
|---|---|
.value | Sets value to be a CSS class for the node content of nodes it is applied to. |
| Namespace token | Meaning |
|---|---|
meta.* | Sets node metadata. |
node.* | Sets node attributes. |
| Tag | Meaning |
|---|---|
[.hidden] | Users have to activate the "show hidden" setting to see these nodes. |
| |
| Node-type | Meaning |
|---|---|
{= text} | Default node-type. Declaration redundant. |
{= hr} | Horizontal rule. |
{= gap} | Vertical whitespace. A separator with no drawn line. |
{= image} | Image element. |
{= block} | Scrollable Markdown section. |
{= iframe} | Arbitrary iframe. |
{= video} | Embeds videos. |
{= tr} | Table row. Must be a child of {= table}. |
{= table} | Table. Header cells defined by label; rows are {= tr} children. |
{= tab} | Combines consecutive {= tab} nodes to create navigable tab list. |
{= badge} | Combines consecutive {= badge} nodes to create 88x31 section. |