Blocks

A block is one paragraph-level unit of the content stream. Its kind is inferred from its spelling in the source syntax (see Kind inference), and its shape determines what content it holds (see the three shapes). The block types available to a script — their labels, styling, behavior, and flow — are declared in config.blocks as an array of BlockDef. Even media — image, audio, video — is just void-shaped block types declared here; no field below is media-specific.

BlockDef

Field Type Required Description
id string Unique kind id. One class-safe token.
label string Display label; default: the id.
shape "text" | "void" | "grid" Content shape; default "text".
grid { cols? } Default column count when authoring a new instance of a grid-shaped kind.
default boolean true on exactly one block — the default Text block.
behavior BlockBehavior Structural flags (below).
indexes IndexDef[] Navigator index groups this kind feeds.
editor BlockEditor Editing behavior — shortcut, placeholder, Enter/Tab flow, allowed sections.
style StyleDecls CSS-subset declarations — the canonical home of a kind’s styling.
syntax object Per-syntax spelling (match + write), keyed by syntax id. See Kind inference.

The default Text block

Exactly one block type must carry default: true. It is the fallback for any content that matches no other kind — a bare paragraph with no distinguishing spelling and no styling of its own. It is the implicit final fallback of kind inference and is never listed in match precedence (it declares no match rules). A config with zero, or more than one, default block is invalid.

BlockBehavior

Structural flags — all optional. Together they express a block type’s role in the document’s outline, numbering, and pagination.

Field Type Default Description
outline boolean false Show blocks of this kind in the outline / navigator. A kind with outline is a division.
rank number Outline nesting rank (1 = top). Only meaningful with outline. Division structure lives here.
numbered boolean false Automatic running number (e.g. scene numbers).
restartNumbering boolean false On a numbered division, restart the count at 1 whenever a coarser division (lower rank) appears — a play’s scenes reset each act. Off = the count runs continuously (screenplay style).
summary boolean false Summarizes the division it opens (the navigator shows an auto-blurb).
printing boolean true false = the block exists in the file but never prints or renders for reading — writer-only notes (Fountain [[…]], boneyard /* … */).
keep object { together?, withNext?, withPrev? } — typography keeps: don’t break inside the block, or don’t separate it from its neighbor (a cue never orphaned from its dialogue).
more string | true Text printed at the foot of a page when this block breaks across pages; true = the default "(MORE)". Localizable.
resumed string | true Text appended to a continued cue — after a page break, and on a consecutive same-index block of this kind; true = the default "(CONT'D)". Localizable.

There is no speaker / cue flag. Speaker identity is derived from indexes — the character list is just an index group — and same-speaker (CONT'D) falls out of resumed combined with index-match equality on consecutive cue blocks. FDX character mapping is an adapter requirement, not a format flag. See the fdx adapter.

Divisions (blocks with outline + rank) are the repeating, ranked headings — Act, Sequence, Scene, Chapter — that form the outline. They are a distinct concept from sections; see that page for the full distinction.

Example — a screenplay scene heading

{
  "id": "scene_heading",
  "label": "Scene Heading",
  "behavior": { "outline": true, "rank": 3, "numbered": true, "summary": true },
  "indexes": [
    { "label": "Locations", "pattern": "^(?:INT\\.?|EXT\\.?|I/E)\\.?\\s+(.+?)(?:\\s+[-–—]\\s+.*)?$" }
  ],
  "editor": { "shortcut": "Mod-1", "enter": "action", "tab": "action", "shiftTab": "transition", "sections": ["body"] },
  "style": { "text-transform": "uppercase", "font-weight": "bold", "margin-top": "1.6rem" },
  "syntax": {
    "html": { "match": [{ "construct": "h3" }], "write": { "tag": "h3" } },
    "fountain": { "match": [{ "prefix": "INT." }, { "prefix": "EXT." }], "write": { "transform": ["upper"] } }
  }
}

IndexDef

An index is a navigator sidebar group — a list of entries collected from the text of blocks of a kind. A character list, a location list, a props list: each is an index.

Field Type Required Description
label string Group label in the sidebar (e.g. "Characters").
pattern string (regex) Regex source run against the block’s text; matches collect into the group.

A block type may declare zero or more indexes. Multiple block types can feed the same label (they merge under one group). This is how the screenplay’s character block populates a Characters index — and, combined with behavior.resumed, how same-speaker (CONT'D) is derived.

BlockEditor

The editing behavior of a block type — its keyboard shortcut, its placeholder, its Enter/Tab flow, and where it’s allowed.

Field Type Description
shortcut string Keyboard shortcut, e.g. "Mod-1" (Mod = ⌘ on macOS, Ctrl elsewhere).
placeholder string Ghost text shown in an empty block.
enter string Kind of the next block created on Enter (a block id).
tab string Kind this block cycles to on Tab.
shiftTab string Kind this block cycles to on Shift-Tab.
sections string[] Allowed section ids (sectioned documents only). Omitted = anywhere. Edge blocks are exempt.

enter / tab / shiftTab are what make a screenplay editor feel like a typewriter: press Enter after a Character cue and you’re in Dialogue; press Tab and Scene Heading cycles to Action. The flow is entirely format data.