Let's start with the basics, so that you can be productive right away! Also, just so you know, each example is a live editor.


A prefix underscore will emphasize a word. Use two for strong emphasis.

One underscore is italics
Two underscores is bold

Brackets can be used to emphasize multiple words or parts of a word.

The apple pie was amazing!

Alternatively you can use the tilde, which is a non-breaking space:


The @@ operator is used to create links. On the left goes the link's label (optional) and on the right, the URL.

Again, you can group with brackets:

Finally, you can put the URL in a variable if you find it more convenient:

Check out my blog!

Also note the use of the tilde above. It is required otherwise the ! is understood to be part of the URL.


The link syntax also serves to display images. Prefix the path with image:

You can give images a title as well:


If you want to control the image's size or other properties you should use the % operator:



Begin a line with one equal sign for a h1 tag, two for a h2 tag, and so on:







An asterisk at the beginning of a line creates a bullet point.

  • Bread
  • Tomatoes
  • Goat cheese

A hash sign, on the other hand, starts an ordered list.

  1. One!
  2. Two!
  3. Three!


A leading + creates a header row and a leading | creates a normal row.


Of course, you may think aligning table elements is a little annoying, or perhaps your table is stored in a JSON file and you would like to make a table automatically for it.


The `:=` operator creates definitions.

A cool markup language.
Not cool at all.


A prefix > will create a blockquote. Consecutive lines will be merged.

Hello, I am a great man

Although, you can use indent, too.

Hello, I am a great man

Multiple blockquote levels can be done, but they require a space between the [>]s.


Code blocks

The ampersand operator creates a code block:

This is a code block

If you wish to highlight the code in a particular language, you need to use the quaint-highlight plugin and then write out the language before the &:

function square(x) {
    return x * x;

This will not work if you don't use the plugin.

Inline code

A prefix backtick makes a word into inline code.

Here is code

Normally you will want to use brackets:

Simple as 1 + 1 = 2

Note that only the outer bracket pair will be stripped off:

Simple as [1 + 1 = 2]

For the rare case where you want to show an unmatched opening or closing bracket as code, escape it with a backslash:

The opening bracket is [


Any block that comes after ;; will be ignored by Quaint:

I have nothing to hide


If you want to print a character without triggering any special meaning it may have, simply prefix it with a backslash.

__Not _emphasized

Also, Quaint thinks every sequence of operator characters is a distinct operator. So while x@@#y looks like a link to #y it is actually an application of the @@# operator, which does not exist. Escaping an operator character makes it a word character, so in that case you can escape # to get the desired behavior:




The spacing between an operator and its operand determine the priority of the operator. More spacing means a larger operand. To put it simply:

One word is bolded
All the words are bolded
One word is linked

Play a bit with the spacing above to get a feel of the results


An indented block after an operator belongs to that operator:

  • This is all inside the bullet point
all inside the strong emphasis
  • You can also put the operator on its own line.


You can group together any chunk of text by enclosing it in square brackets ([]). They effectively behave like a single word.

Brackets do not show up
Emphasis on one word
Emphasis on many words
Here is a link
Here is another link

HTML Generation

The % operator is used to generate arbitrary HTML nodes, if you need to. The full syntax looks like this:

tag#id.class %
  attribute = value

You can specify multiple classes. If there is no tag, the default is div.


An error occurred! (Not really)

You can also write the nodes more compactly by putting every property and element inside square brackets.

A link to google!


Now here's what will not work. % cannot be used as a suffix operator without adding a space (this is so that you can say that 100% of crows are black or the glass is 50% full without creating tags, which would be confusing). With a space before %, it will create a tag, but with the space comes the need for grouping brackets. So a line break, for example, is [br %]:

First br% line
Second line

Notice how the first br% is just shown normally and does not create a <br> tag, whereas [br %] does!

Also, because of Quaint's fixed priorities (all operators are right-associative), this will not work as intended (it creates a <klass> tag):


To make it work, put spaces around %, or brackets around span.klass.


html macro

Alternatively, you can embed HTML directly using one of these two methods:

x2 x2

Inject CSS

Injecting CSS!

Oranges are orange!

Inject JavaScript

Note that this is different from embedding JavaScript: what I mean by inject is to write code inside the generated HTML, with script tags. This is done as follows:

js :: javascript code

For example,

js :: console.log("hello")

will print “hello” to the console when you load the page in the browser. It will do nothing at generation time.

HTML Sandbox

Let's generate HTML!

  1. 22 is 4
  2. 222 is 16
  3. And so forth...


If there is a piece of markup you don't want to put in the middle of a paragraph, for example a long URL for a link, or want to use multiple times, then variables are for you. It's very simple:

variable => contents

For example:

Theropods are a family of dinosaurs which, according to the study by Smith, had very large wings that allowed them to fly to the moon.

Better yet… you can define the variable after it is used, and it will work anyway!

Quaint is a language similar to Markdown with a dash of Haml

A variable can be used multiple times.



Simply put, a rule is a reusable template that you assign a name or an operator to. Rules help with terseness and code reusability, although abusing them could make your code difficult to read. The syntax for a rule is:

[pattern] => template

A pattern is a normal Quaint expression, but any word which is prefixed with a backslash becomes a variable. The variable can be inserted in the template using curly brackets ({variable}). Here is an example of a rule someone may write to make superscripts easier:


Both arguments must be present in order for the rule to work. If either is absent, for instance ^2 lacks the text argument, the rule will not be run. You can change this by declaring the argument as \maybe\text instead:

23 and 3 match, but 2^ does not

Conversely, if you declare the pattern [^ \superscript], Quaint requires the operator to be prefix:

3 matches, but 2^3 and 2^ do not


Rules do not modify Quaint's parser: the ^ operator has always existed, it is just that by default it just prints itself out. This is an advantage, because rules in Quaint are predictable: the operator we just defined is right-associative, because all operators in Quaint are right-associative. They are sensitive to spacing like all operators, they can be bracketed like all operators, and so on.

  • Superscript one word
  • Superscript multiple words
  • Right associative: 23456
  • Emphasizedsuperscript
  • Superscripting a whole block!

Rule Sandbox

I am a big fan of oranges and other orange food like carrots.

The orange is a fruit, who would have thought?


Curly brackets switch to “eval mode”. They could contain JavaScript, or Earl Grey, or something else. By default the “eval” used is just a key-based load/store mechanism. Other scripting languages require importing a plugin.

Supposing the quaint-javascript plugin is used, as it is on this site, then you can embed JS expressions:

2 + 2 = 4

You can also use JS inside rules. The variables declared by the rule are also available in JavaScript! They are not strings, but you can convert them into strings by calling the raw method on them.


It is also possible to build HTML programmatically. quaint-javascript comes with the h function. If you use h, though, make sure to call engine.gen on the arguments to apply Quaint markup to them! Unless you are converting them to strings, that is. The markup will be lost if you do that.

This is bold!

With the quaint command line and API, you can provide environment variables for use inside curly brackets. See the -d option for the quaint command.


Generate something different depending on the value of a variable or of metadata with conditionals:

First there is the condition ?? iftrue construct:


You can add a branch to generate when the condition expression is false with the !! operator.


cond !! iffalse is shorthand for cond ?? cond !! iffalse.


{true} and {false} trivially evaluate to true or false respectively, but they are not super useful.

On metadata

Meta variables, when they are not defined, will trigger the false branch:


They also trigger the false branch if they are set to “false":

  • no

On variables

As conditionals, you can use variables imported with include @@ #include, with the -d flag of the command line, or set by setenv

  • yes
  • no


The each macro can be used to generate loops over various data. The syntax is:

each data variable ::

each data var1 var2 ... ::

There are many kinds of data you can iterate on:

On lists

  1. I need bread
  2. I need milk
  3. I need bananas

On tables

Depending on whether it has a row of headers, a table is interpreted either as a list of objects or as a list of lists:

With a header, it is a list of objects:

  • Alice is 21 years old and is a baker
  • Bob is 42 years old and is a banker
  • Carmen is 33 years old and is a fraud

Without, you have to declare a variable for each column, just like this:

  • Alice is 21 years old and they are a baker
  • Bob is 42 years old and they are a banker
  • Carmen is 33 years old and they are a fraud

On documents

  • Hello, Alice
  • Hello, Bob

On metadata

  • Tagged: Cool!
  • Tagged: Wow!


  • Hello, Alice!
  • Hello, Bob!
  • Alice is a baker
  • Bob is a banker

This works just as well if you include external data, of course. Also, check out the quaint-yaml plugin if you wish to include and iterate over YAML.


Macros are typically written with the :: operator, either as macro :: body or macro argument :: body.


See here


Generate a doctype tag for a document:

doctype :: html
==> <!DOCTYPE html>


data reads a data file and returns it (usually so you can put it in a variable)

For example:

movies => data :: movies.json

= List of movies!
each {movies} movie :: * {movie.title}

Also consider the quaint-yaml plugin if you wish to fetch YAML data:

plugins :: yaml
movies => data :: movies.yaml


See store


See Loops


See here


include reads a file and then does something special with it:

include :: template
include :: template.q
include :: data.json, other-data.json

Also consider the quaint-yaml plugin if you wish to include over YAML:

plugins :: yaml
include :: data.yaml


meta lets you declare metadata: title, author, and so on. It also lets you print out the data elsewhere in the file.

You are reading My Life by Me!.


This imports a plugin directly from Quaint. It won't work here in the browser, but it will offline.

The syntax works like this:

plugin name ::
  option = value

For example:

plugin highlight ::
  defaultLanguage = python

You will need to install the corresponding packages locally. For instance, for the highlight plugin to work, you need to execute this command beforehand:

npm install quaint-highlight


This is shorthand to import plugins with their default options:

plugins :: highlight javascript

This will import quaint-highlight and quaint-javascript with their default options.


The resources macro lets you include files in your output. By default, the resources will be inserted in the head tag.

resources ::

Depending on command-line options, the resources may be copied over to a resource directory and linked to, or inlined directly in the output (at the appropriate location). The default is to copy and link.


scope creates a new scope, so that all variables declared in the body are only visible inside that body.



store is mostly useful in conjunction with the API and/or templates. With this macro you can push data to an internal “document" (a list of references, or a list of script tags to put in <head> for instance), and then dump that document somewhere convenient. You don't have to dump after everything has been stored.

  1. Bob
  2. Clara
  3. Damian

One use case of store is in Quaint's very documentation. The code for this page declares:

store sidebar ::

That is to say, “put the table of contents in the sidebar”. Then, the template it is using dumps the contents of the sidebar document in the sidebar.

You can also use store and dump along with each.

  1. Bob Clara
  2. Damian

Notice, however, that Bob and Clara are part of the same element as far as each is concerned.


Define the template to use for this file. For example, if you specify

template :: mytemplate

The Quaint compiler will go through the following steps:

  1. Generate the HTML for the whole file
  2. Put the HTML in the variable body
  3. Fetch mytemplate.q
  4. Go to 1 (with the original in the variable body)

So if mytemplate.q contains:

#header % header
#footer % footer

Then any file that uses it as a template will generate a header div above and a footer div below.

The CLI lets you specify a template directory with the -t options. You can also customize how files are read.

Two templates are defined by default and can be used directly:

Plugins can define more templates that use the @ syntax. Check their documentation.


toc prints out a table of contents based on the headers declared in the markup. It can be used anywhere in the file.



Two point one

Two point two



Alternative notation for the ?? operator. They both work identically.


See conditionals

Error reporting

If an error occurs in a Quaint document, the error will be inlined inside a span with class error (which you can style yourself, for example I suggest using bold red, so you don't accidentally skim over your outrageous blunders).

There is an ReferenceError: error is not defined here.

If you want more information about an error, a stack trace for example, you can dump the errors sub-document. Each error will contain a link to its corresponding stack trace.

An error ReferenceError: blah is not defined [#1] and another SyntaxError: Unexpected end of input [#2], woe is me!

E.match: 'Error? e' could not find a match for value 'ReferenceError: blah is not defined' [#3]