Sections & divisions

ScriptPub has two kinds of structure, and keeping them apart is the single most important thing to understand about the model. They never mix.

Section Division
What A unique, named point in the stream. A repeating, ranked heading derived from a block kind.
Examples Title page, Foreword, Body, Appendix, Notes, Footnotes. Act, Sequence, Scene, Chapter.
How many Each occurs at most once. Repeats freely.
Declared by config.sections — a SectionDef. A block type’s behavior.outline + rank.
Nests? Never (points can’t). Yes — by rank.

Sections are the singular, named parts of a work. Divisions are its anonymous, repeating skeleton. A screenplay has one Body section containing many Scene divisions; it does not have a “scene section.”

Sections

A section is a point in the text stream — a named position, not a container. Everything from a section’s point up to the next point (or end of file) belongs to it.

  • Sections are optional. No sections = the whole stream is unsectioned.
  • Sections never nest — points can’t contain points.
  • Each section occurs at most once (one id, one point — there are no two title pages).
  • Config order does not matter. sections is a set; document order is the ground truth. The parser resolves points top to bottom as it scans the stream.
  • A syntax may impose sections. FDX, for instance, always has exactly two (a title page and a body) — a built-in, non-editable constraint of that adapter.

SectionDef

Field Type Required Description
id string Unique section id. One class-safe token.
label string Display label; default: the id.
syntax object Per-syntax expression of the section’s point, keyed by syntax id (below).

Expressing a point

Each section declares, per syntax, how its point manifests. There are two mechanisms, and a document may mix them freely — everything normalizes to points.

1. Wrapper — an element that contains the section’s blocks. In HTML this is a header / section / footer / div (disambiguated by the same class-then-tag inference as blocks — two <section> wrappers need distinct classes). The wrapper’s start is the point; its end is decorative — a block sitting after the wrapper closes but before the next point still belongs to that section. On save, the serializer normalizes the wrapper to match the point model.

{ "wrapper": { "tag": "header", "class": "title-page" } }

2. Derived point — the section begins at the first or last occurrence of a block kind. This is the only mechanism in syntaxes with no container concept (Markdown, plain text, Fountain).

{ "at": "first", "block": "appendix-title" }
{ "at": "last",  "block": "notes-heading" }

last suits trailing sections — “everything from the last notes heading on.”

The screenplay preset’s sections, for example:

"sections": [
  { "id": "title",     "label": "Title page", "syntax": { "html": { "wrapper": { "tag": "header",  "class": "title-page" } } } },
  { "id": "body",      "label": "Body",       "syntax": { "html": { "wrapper": { "tag": "section", "class": "body" } } } },
  { "id": "notes",     "label": "Notes",      "syntax": { "html": { "wrapper": { "tag": "section", "class": "notes" } } } },
  { "id": "footnotes", "label": "Footnotes",  "syntax": { "html": { "wrapper": { "tag": "footer",  "class": "footnotes" } } } }
]

In HTML, <main> is the adapter-managed content root — never a section wrapper. Sections are header / section / footer / div elements inside <main>; edge blocks are direct <main> children.

Edge blocks

If sections are defined, every block falls into some section — with one exception at the document’s edges. Blocks before the first point, and blocks after the final section’s wrapper close when no further point follows, are edge blocks: they belong to no section.

Edge blocks are real blocks — rendered and styled normally per their block kind — but they carry no section styling, are exempt from section placement rules, and are skipped by section-scoped features. There are no implicit or unnamed sections; a Project Gutenberg boilerplate header and license footer become edge blocks without inventing fake sections for them.

Mid-document there are no gaps: between one point and the next, everything — including content after a decorative wrapper close — belongs to the earlier section. (This is exactly what the SectionSpan.end captures.)

Divisions

A division is a repeating structural heading — Act, Sequence, Scene, Chapter — that forms the document’s outline. Divisions are not declared separately: a block type becomes a division by carrying behavior.outline and a rank.

  • rank sets nesting depth — 1 is the top level (Act), higher numbers nest under it (Sequence 2, Scene 3). The outline indents by rank.
  • numbered gives a division an automatic running number; restartNumbering resets that count under each coarser division (a play’s scenes reset per act, where a screenplay’s run continuously).
  • summary attaches an auto-blurb to a division’s outline entry.

The outline and the character/location indexes are derived views over the content — they are computed from the blocks, never stored as structure.