recital / SPEC.md
SPEC.md
Raw

Recital Spec

Introduction

Recital is a markup language and a set of parsers originally meant for writing prose.

It's meant to be extensible -- the core Recital parser creates a bunch of tokens, which can then be parsed by various exporters to produce output files in various formats (at time of writing, HTML, Fountain, and Ink).

It's meant to integrate with other markup languages; Recital itself only cares about the structure of a document, and leaves inline markup and other formatting to exporters. It's meant to be used in tandem with another markup language like Markdown to produce fully formatted documents.

File Type

Prefer using the .stage file format for Recital documents.

Paragraphs & Block Format

The way Recital handles line breaks and individual blocks is inspired by how it works in Markdown, specifically the CommonMark spec: https://spec.commonmark.org/0.29/#blocks. Texts are broken down into scenes, then fragments, and then paragraphs - which can each carry their own metadata.

By default, Recital does not have any considerations for inline markup, and specific inline markup is handled by individual exporters.

Indentation

Recital allows variable indentation for structure reasons, and strips out any indenting before processing the rest of the file.

Line breaks

Single line breaks are considered full section breaks, and equivalent to double linebreaks; both of them create distinct text blocks.

Soft Line breaks

Ending a line with a backslash tells the parser that, logically, that line should be a single line, not a new paragraph break.

This is a paragraph.
This is another paragraph.

This is a paragraph with a soft linebreak. \
This is part of the same paragraph as before.

Code and pre tags

Text that is fenced by the Markdown code tags (three graves), or with <pre></pre> HTML tags will not be formatted, and keep all whitespace, as well as retaining the surrounding tags.

If you want to keep whitespace without having the connotation of being a code or a pre tag, you can do so by surrounding your text with !== tags:

!==
	All whitespace here will be preserved.
!==

The core Recital parser doesn't handle most inline markup, but many libraries and tools support wikilinks, which can be used as an alternative link markup:

This is a [[wikilink]] that should ideally link to the scene with the same title. (Note that wikilinks tend to link to titles rather than ids, due to how they are displayed.)

Like Twine's Chapbook, you can also have display text different from the link's contents, similar to Markdown links:

[[This is a link label->the scene title to go to.]]

Comments

Lines that start with = are comments, and are ignored by the parser.

This is a paragraph.
= This will be ignored.

Structure

Scenes

Scenes are the highest level of organization, and can even logically separate into separate files. By default, in HTML, they are represented with <section> tags.

They are by default delineated by a single # on its own line, separated by empty lines (with possible metadata under it) -- similar to how scenes are separated in standard manuscript format.

All text has to be in a scene, so the very first scene does not need to be preceded by the #

This text is in the first scene.

#

This is in the second.

The extra newlines are important here!

Alternate Scene Definitions

You can also define scenes with a # followed by a :, which allows you to write some metadata after the definition. Anything written on the line with the # does not show up as final output text in the scene's contents.

#

This is a scene

#:

This is also a valid scene

#: blah blah blah

The 'blah blah blah' above is considered the scene's title.

# This is a header, not a scene

Metadata

There are two methods to add metadata to a Recital scene: via block metadata, or inline metadata.

You add metadata to scenes via Block Metadata, by putting the metadata in between --- or +++ tags below the #:

#
---
note="Scene metadata goes here"
---

In order to use Inline Metadata, you have to create your scene tag starting with #: before adding metadata to it. Note that the : is optional if you don't want / need inline metadata -- I generally like the bare # if the only thing that's needed is a proper separator.

#: This is a scene with inline metadata

Scene contents

Because # is also used for headings in Markdown and other markup languages, you cannot write any inline metadata with the base tag! Without the extra :, the # will be ignored.

Metadata is written in TOML.

You can also add both block and inline metadata to the same scene. In this case, if a property appears in both the inline and block metadata, the block version will take priority.

#: A scene with both block and inline metadata id="inline-id"
---
id="block-id"
position.x=5
position.y=10

The resulting metadata object will have an id of block-id.

Fragments

Fragments are sections of text that are encapsulated into their own sections, which can be shown or hidden or linked to.

Text can be outside of fragments, or inside a single fragment. Fragments cannot be nested; starting a new fragment will close the previous one.

<>

Fragments are enclosed within empty brackets.

</>

This section is outside a fragment.

You can also omit the closing bracket to have a fragment link to another fragment:

<>

Fragment 1

<>

Fragment 2

Metadata

You can add metadata to fragments by putting that metadata on the same line as the opening bracket for a fragment as Inline Metadata:

<> Inline meta for a fragment

...or as Block Metadata, underneath the opening <> tag, delineated by --- or +++:

<>
+++
id="fragment-id"
+++

Fragment contents

All metadata is written in TOML. For inline metadata, the metadata will be delineated by spaces that aren't in quotes. Arrays will not work properly in inline metadata.

Similarly to scenes, you can define both block and inline metadata for fragments, with block metadata taking precedence.

Paragraphs

All paragraphs are separated by one or two newlines.

Paragraphs cannot get any default metadata like blocks and scenes do. However, they can get arbitrary metadata via @ shorthand or post-section meta tags, which are put after the paragraph.

Metadata

Paragraphs can be decorated by @-shorthand metadata to define ids and classes. The @ precedes the paragraph, and is separated by a space or a colon and a space:

@paragraph-class This paragraph is decorated with an @.

Free-form Meta

You can define additional, free-form metadata for each paragraph by using double brackets to enclose any string on the line immediately following the paragraph.

Example
This is a paragraph.

This is a paragraph with additional arbitrary metadata attached to it.
<! The arbitrary metadata is written between `<! this tag >` on the line below the paragraph >

@class You can attach this metadata to paragraphs with @ shorthand or other existing div logic as well.
<! Metadata also
respects newlines >

The stage parser currently will take the metadata for each paragraph, and put it into the _ field of the resulting object. Different export programs can then read the information from that field and perform additional operations on it.

For fragments and scenes, this is functionally identical to writing _="contents" within the TOML metadata.

Metadata

Notes common to multiple metadata methods.

Block Metadata

Block-type metadata can be attached to both scenes and fragments, and are written in TOML.

They are created by creating a frontmatter tag on the line immediately after the definition of the scene or the fragment, and are closed with the same tag.

Frontmatter tags are either --- or +++:

#
---
note="This is the block-level metadata"
---

Top-level scene content

<>
+++
note="This is block-level metadata for the fragment. Note that you can use either --- or +++
+++

Fragment content

</>

Inline Metadata

Inline metadata can be attached to both scenes and fragments, and are written on the same line as the scene or fragment definition:

#: Inline meta for a scene

<> Inline meta for a fragment

It's possible to put TOML in there as well:

<> id="fragment-id" @at-shorthand.works.here

This is the fragment content.

Note that inline metadata cannot span more than a single line, unless you use soft line breaks to functionally make it a single line.

Inline meta follows the following rules:

  • Properties are separated by spaces, but adding quotes around strings will preserve those spaces
  • properties that start with @ are parsed as @-shorthand
  • properties that have an = in them (no spaces) are processed as TOML
  • If there has not been any TOML or @-shorthand properties yet, the first plaintext string property (including spaces) is designated as the page's title.
  • Block meta always takes precedence over inline meta

Titles

Inline metadata is often used to identify scenes and fragments, by giving easier shorthand for writing title, id, and classes for those elements.

If you use inline metadata, the title of a scene or fragment is considered to be all of the properties immediately after the delineator, up until you reach a property that uses TOML or @-shorthand. Titles can have spaces in them, and do not need to be wrapped in quotes.

#: This is the title of a scene

The title will be 'This is the title of a scene'

#: Titles stop if there @is an at-shorthand in the middle

The title will be 'Titles stop if there'

#: @#id This one will have no title, since we started with a shorthand

The title will not exist

#: TOML also foo="bar" break titles

The title will be 'TOML also'

Top-level metadata

After parsing into JSON, most metadata for scenes and fragments can be found in the meta object for that scene or fragment.

However, there are a few that are pulled out to top level, since they may be useful for other contexts. They are:

  • id - a string id for the scene / block, akin to the HTML id tag. Must not contain spaces, and must begin with an alpha.
  • classes - a string[] array of classes for the scene / block, akin to the HTML class tag. A single class cannot contain spaces.
  • primary - see the section further ahead. The first class or id associated with the scene or fragment, which can be used to link to it.
  • title - title of the scene or fragment. Can be used by wiki style links to link to this scene or fragment, or displayed in other ways.

@ shorthand

Ids and classes for fragments or paragraphs can be written in @ shorthand, which is put inline in the metadata fragment or before the line in a paragraph.

In @ shorthand, all classes and ids are written in a row, separated by . to start classes, or # to start ids. By default, the first element in a shorthand is a class, unless it is prefixed by #. A single @ shorthand can only have one id, but can have multiple classes.

<> @#id.class.class2

@#id-for-paragraph This paragraph is decorated by @ shorthand! You can just have a space afterwards, or use a colon to separate the shorthand from the paragraph content.

@class This is a second decorated paragraph.

This is useful for dialogue:
@character-1 Hello.
@character-2 Hi!

primary

The first class (or id) after writing the @ symbol in @ shorthand is known as the primary identifier. If there is only a single class or id in the @ shorthand, then that one is also the primary.

@player The primary will be 'player'
@listener.guest The primary is 'listener', but there are two classes 'listener' and 'guest'

@speaker#id 'id' is a unique id, but the primary is still 'speaker' because it was listed first.

Logic

Logic is anything that can alter the appearance of a story, or that isn't part of the narrative or the meta for a specific passage. Ideally, for static exports, all the logic tags can be stripped out and you'll see the whole story as-is (though it might not be as interesting).

All logic tags begin with $ so they can be removed by specific parsers.

All logic tags have a name (which is written after the $ with no space), and then zero or more arguments, separated by spaces. Arguments with spaces can be wrapped in double-quotes.

$clear
$pause 400
$log "This is a long parameter with spaces"

Logic is very specific to different exports, so will be detailed in various extensions.