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.
sectionsis 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 areheader/section/footer/divelements 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.
ranksets nesting depth —1is the top level (Act), higher numbers nest under it (Sequence2, Scene3). The outline indents by rank.numberedgives a division an automatic running number;restartNumberingresets that count under each coarser division (a play’s scenes reset per act, where a screenplay’s run continuously).summaryattaches 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.