Marks & links
A mark is inline formatting applied to a run — bold, italic, underline,
small-caps, a link, ruby annotation. Marks are declared in config.marks as an
array of MarkDef, and applied in the model’s runs — to
text runs and to object runs
alike (a linked inline image is an object run under an href mark). Like block
types, marks nest freely, and their definition order is their inference
precedence.
MarkDef
| Field | Type | Required | Description |
|---|---|---|---|
id |
string |
✓ | Unique mark id. One class-safe token. |
label |
string |
Display label; default: the id. | |
editor |
object |
{ "shortcut": string } — e.g. "Mod-b". |
|
style |
StyleDecls |
Inline-safe CSS-subset declarations (only the mark-legal properties — see Styling). | |
syntax |
object |
Per-syntax spelling, keyed by syntax id. |
A mark’s per-syntax spelling mirrors a block’s but is simpler:
MarkSyntax = { match?: MarkMatch[], write?: MarkSpelling }
MarkMatch = { construct?: string, class?: string } // inline tag + class (HTML), or a marker name
MarkSpelling = { tag?: string, class?: string, delim?: string, construct?: string }
tag/class— the HTML inline element and class.delim— the Markdown / Fountain delimiter ("*","**","_"; a Markdown link is"[]").construct— the FDX textStylename (Bold/Italic/Underline/Strikeout).
HTML mark inference is class-then-tag, exactly like blocks: a <span class="x">
matches the mark claiming that class before any mark claiming bare <span>.
Example
{
"id": "em",
"label": "Italic",
"editor": { "shortcut": "Mod-i" },
"syntax": {
"html": { "write": { "tag": "em" } },
"md": { "write": { "delim": "*" } },
"fountain": { "write": { "delim": "*" } },
"fdx": { "write": { "construct": "Italic" } }
}
}
A mark with no match in a syntax is not inferred there, but can still be
written — so a mark can round-trip through a syntax that can only express it on
serialize.
Links
A link is a mark carrying an href attribute (so its MarkUse takes the
object form, { id, attrs: { href } }). It may also carry a title — the
CommonMark [text](href "title") title, HTML’s <a title>; support is tiered
like any attribute. There are two target species:
External links
An external href is a URL of any scheme. It is available wherever the syntax can
spell a link — HTML <a>, Markdown [text](url). Support is tiered: Fountain,
for example, has no link syntax, so an external link does not survive a round-trip
through it.
Internal links
An internal href is a reference into the document, #-prefixed. Resolution
precedence:
| Form | Resolves to |
|---|---|
#^<id> |
A block ref — the block carrying that id. |
#<section-id> |
A section ref — a config.sections[].id. |
#<name> / running number |
A structural ref to a division — by heading text or running number (“Scene 12”), resolved against the derived outline. |
Structural refs work in every syntax and need no stored id — but renaming a heading breaks links to it (as in Markdown or a wiki); an editor may offer to fix references.
Ids are written on demand
A block carries a persisted id in the file only if something targets it — a
link, a translation origin anchor — or the user pinned
one. The parser never mints ids into the file; ephemeral editor-internal ids are
separate and non-persisted. Each syntax has its own id spelling: HTML’s id
attribute, Markdown’s Obsidian-style trailing ^id, FDX element ids, JSON
trivially. This “on-demand” rule is what keeps content-derived syntaxes lossless —
nothing is written that the text doesn’t need.