@heroiclands/package-build 23.0.0 → 23.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +1 -1
  3. package/bin/content-commands.mjs +1 -1
  4. package/ci/content-format-reference.mjs +46 -0
  5. package/docs/api.md +124 -141
  6. package/docs/authoring/assets.md +1 -1
  7. package/docs/authoring/dates-and-calendars.md +12 -6
  8. package/docs/authoring/frontmatter.md +2 -2
  9. package/docs/authoring/links-and-markup.md +145 -29
  10. package/docs/commands.md +8 -10
  11. package/docs/configuration.md +13 -11
  12. package/docs/content-format.md +2 -2
  13. package/docs/guides/book.md +59 -4
  14. package/docs/guides/icons.md +4 -5
  15. package/docs/guides/packs.md +6 -0
  16. package/docs/guides/reference-pages.md +21 -1
  17. package/docs/guides/release-and-deploy.md +17 -1
  18. package/docs/guides/site.md +17 -18
  19. package/docs/reference/format-details.md +877 -276
  20. package/docs/reference/note-types.md +278 -91
  21. package/docs/reference/theme-pages.md +58 -97
  22. package/engine/address-values.mjs +124 -4
  23. package/engine/address.mjs +44 -3
  24. package/engine/anchors.mjs +103 -3
  25. package/engine/art-slots.mjs +2 -9
  26. package/engine/base-compiler.mjs +25 -6
  27. package/engine/calendar-artifacts.mjs +4 -1
  28. package/engine/calendar-notes.mjs +166 -102
  29. package/engine/content-format-check.mjs +2 -3
  30. package/engine/content-format.mjs +44 -1
  31. package/engine/content-format.yaml +79 -16
  32. package/engine/content-images.mjs +10 -1
  33. package/engine/content-index.mjs +37 -9
  34. package/engine/content-links.mjs +24 -5
  35. package/engine/content-tables.mjs +24 -3
  36. package/engine/data-keys.mjs +347 -0
  37. package/engine/derived-sections.mjs +322 -0
  38. package/engine/diagnostics.mjs +28 -0
  39. package/engine/event-fields.mjs +187 -0
  40. package/engine/event-rows.mjs +126 -0
  41. package/engine/event-views.mjs +305 -0
  42. package/engine/exported-scene.mjs +29 -53
  43. package/engine/frontmatter-lint.mjs +103 -77
  44. package/engine/frontmatter.mjs +7 -2
  45. package/engine/generate.mjs +53 -0
  46. package/engine/generated-sections.mjs +223 -0
  47. package/engine/heading-attributes.mjs +4 -2
  48. package/engine/helpers.mjs +12 -1
  49. package/engine/holdings.mjs +12 -33
  50. package/engine/ids.mjs +17 -11
  51. package/engine/index.mjs +4 -4
  52. package/engine/infobox-render.mjs +21 -6
  53. package/engine/infobox.mjs +217 -99
  54. package/engine/journals.mjs +104 -47
  55. package/engine/literature-notes.mjs +4 -1
  56. package/engine/literature-works.mjs +21 -13
  57. package/engine/map-graphviz.mjs +4 -18
  58. package/engine/markdown-expressions.mjs +116 -11
  59. package/engine/metadata-index.mjs +26 -0
  60. package/engine/near-miss.mjs +90 -0
  61. package/engine/note-addresses.mjs +75 -19
  62. package/engine/note-dates.mjs +5 -3
  63. package/engine/note-event-terms.mjs +364 -0
  64. package/engine/note-events.mjs +823 -0
  65. package/engine/note-vocabulary.mjs +184 -88
  66. package/engine/office-holders.mjs +20 -54
  67. package/engine/packagebuild-index.mjs +16 -1
  68. package/engine/pdf-build.mjs +97 -60
  69. package/engine/pdf-index.mjs +263 -0
  70. package/engine/pdf-render.mjs +47 -5
  71. package/engine/place-relation-terms.mjs +174 -0
  72. package/engine/place-relations.mjs +72 -160
  73. package/engine/rank-ladder.mjs +14 -41
  74. package/engine/reckoning-markers.mjs +2 -0
  75. package/engine/region-events.mjs +6 -12
  76. package/engine/scenes.mjs +73 -468
  77. package/engine/site-build.mjs +75 -101
  78. package/engine/site-index.mjs +3 -1
  79. package/engine/site-maps.mjs +43 -29
  80. package/engine/site-preview.mjs +40 -31
  81. package/engine/social-ties.mjs +2 -1
  82. package/engine/sql-tables.mjs +212 -9
  83. package/engine/standing-terms.mjs +145 -6
  84. package/engine/standings.mjs +37 -49
  85. package/engine/web-wikilinks.mjs +21 -1
  86. package/engine/wikilink-syntax.mjs +34 -4
  87. package/engine/wikilinks.mjs +27 -2
  88. package/hugo-theme/layouts/partials/infobox/entry.html +4 -1
  89. package/hugo-theme/layouts/partials/page-body.html +0 -3
  90. package/hugo-theme/static/css/style.css +25 -55
  91. package/package.json +1 -2
  92. package/packagebuild-metadata.jsonl +13 -13
  93. package/sohl/note-schemas.mjs +8 -73
  94. package/types/engine/address-values.d.mts +50 -3
  95. package/types/engine/address.d.mts +21 -0
  96. package/types/engine/anchors.d.mts +49 -2
  97. package/types/engine/art-slots.d.mts +1 -1
  98. package/types/engine/base-compiler.d.mts +13 -4
  99. package/types/engine/calendar-notes.d.mts +7 -0
  100. package/types/engine/content-format.d.mts +52 -0
  101. package/types/engine/content-images.d.mts +5 -1
  102. package/types/engine/content-tables.d.mts +9 -1
  103. package/types/engine/data-keys.d.mts +145 -0
  104. package/types/engine/derived-sections.d.mts +73 -0
  105. package/types/engine/diagnostics.d.mts +15 -0
  106. package/types/engine/event-fields.d.mts +99 -0
  107. package/types/engine/event-rows.d.mts +12 -0
  108. package/types/engine/event-views.d.mts +67 -0
  109. package/types/engine/exported-scene.d.mts +5 -2
  110. package/types/engine/frontmatter-lint.d.mts +3 -3
  111. package/types/engine/generated-sections.d.mts +143 -0
  112. package/types/engine/holdings.d.mts +6 -20
  113. package/types/engine/ids.d.mts +15 -12
  114. package/types/engine/index.d.mts +1 -1
  115. package/types/engine/infobox.d.mts +13 -3
  116. package/types/engine/journals.d.mts +24 -11
  117. package/types/engine/literature-works.d.mts +1 -2
  118. package/types/engine/map-graphviz.d.mts +2 -10
  119. package/types/engine/markdown-expressions.d.mts +12 -3
  120. package/types/engine/near-miss.d.mts +42 -0
  121. package/types/engine/note-addresses.d.mts +7 -1
  122. package/types/engine/note-event-terms.d.mts +68 -0
  123. package/types/engine/note-events.d.mts +71 -0
  124. package/types/engine/note-vocabulary.d.mts +37 -8
  125. package/types/engine/office-holders.d.mts +3 -0
  126. package/types/engine/pdf-index.d.mts +35 -0
  127. package/types/engine/pdf-render.d.mts +8 -2
  128. package/types/engine/place-relation-terms.d.mts +83 -0
  129. package/types/engine/place-relations.d.mts +11 -66
  130. package/types/engine/rank-ladder.d.mts +2 -0
  131. package/types/engine/region-events.d.mts +6 -12
  132. package/types/engine/scenes.d.mts +6 -32
  133. package/types/engine/site-build.d.mts +8 -22
  134. package/types/engine/site-maps.d.mts +15 -7
  135. package/types/engine/sql-tables.d.mts +77 -2
  136. package/types/engine/standing-terms.d.mts +37 -4
  137. package/types/engine/standings.d.mts +14 -9
  138. package/types/engine/wikilink-syntax.d.mts +20 -0
  139. package/types/engine/wikilinks.d.mts +3 -2
  140. package/docs/guides/government-migration.md +0 -52
  141. package/engine/itinerary-scenes.mjs +0 -166
  142. package/engine/lore-events.mjs +0 -197
  143. package/engine/map-notes.mjs +0 -1309
  144. package/engine/map-raster.mjs +0 -51
  145. package/hugo-theme/layouts/partials/holdings/entry.html +0 -21
  146. package/hugo-theme/layouts/partials/holdings/kind-groups.html +0 -71
  147. package/hugo-theme/layouts/partials/holdings.html +0 -61
  148. package/hugo-theme/layouts/partials/literature-works.html +0 -29
  149. package/hugo-theme/layouts/partials/place-map.html +0 -9
  150. package/types/engine/itinerary-scenes.d.mts +0 -29
  151. package/types/engine/lore-events.d.mts +0 -14
  152. package/types/engine/map-notes.d.mts +0 -297
  153. package/types/engine/map-raster.d.mts +0 -8
package/docs/api.md CHANGED
@@ -104,7 +104,8 @@ Deterministic document ids, derived by hashing rather than stored, so compile pa
104
104
  | ---------------------- | ----------------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
105
105
  | `makeId` | `makeId(namespace, value)` | `string` — a 16-character hexadecimal Foundry id | deriving a stable id from a namespace and a value, e.g. a heading id when none is supplied |
106
106
  | `MAP_TYPES` | `const MAP_TYPES` | — | enumerating the content types that compile into a Foundry `Scene` |
107
- | `MAP_SUBTYPES` | `const MAP_SUBTYPES` | — | reading the map subTypes, which differ only in derived canvas defaults |
107
+ | `isMapType` | `isMapType(type)` | `boolean` | asking whether a content note's type compiles into a Scene |
108
+ | `MAP_SUBTYPES` | `const MAP_SUBTYPES` | — | reading the map subTypes, each of which carries an exported Scene |
108
109
  | `JOURNAL_TYPES` | `const JOURNAL_TYPES` | — | enumerating content types whose whole document _is_ a JournalEntry |
109
110
  | `NO_PACK` | `const NO_PACK` | — | spelling the `pack:` value (`none`) that routes a note's document into no compendium |
110
111
  | `PACK_BY_TYPE` | `const PACK_BY_TYPE` | — | looking up the conventional pack name and document type for a content type |
@@ -352,29 +353,29 @@ The note types the engine itself declares — vocabulary that is a fact about th
352
353
 
353
354
  An addressed content note accepts exactly these top-level keys, in this order: `shortcode`, `name`, `type`, `subType`, `description`, `tags`, `data`, `dnd5e`, `hm3`, `sohl`. A key outside this list is an error at its own line. The system blocks are one per system the address vocabulary recognizes, sorted by name after the fixed keys, so a further system is a change to `SYSTEM_IDS` alone. No dnd5e-specific document types are declared. Within that shape, the closed vocabularies are the `data:` container and each type's `subType`.
354
355
 
355
- | Export | Signature | Returns | Use it when |
356
- | ------------------------- | -------------------------------------------- | ---------------------------------------- | -------------------------------------------------------------------------------------------- |
357
- | `DRAFT_TAG` | `const DRAFT_TAG` | — | naming the declared tag that marks a note as unfinished |
358
- | `GM_TAG` | `const GM_TAG` | — | naming the declared tag that marks a GM-only note |
359
- | `BEING_ARCHETYPES` | `const BEING_ARCHETYPES` | `Readonly<Record<string, string>>` | looking up the case-sensitive being archetypes and their meanings |
360
- | `NOTE_VOCABULARY` | `const NOTE_VOCABULARY` | — | looking up, per content type, its `data:` field list and its closed `subType` values |
361
- | `NOTE_TOP_LEVEL_FIELDS` | `const NOTE_TOP_LEVEL_FIELDS` | `readonly TopLevelFieldSpec[]` | reading the top-level keys a note accepts, in formatted order, with what each one means |
362
- | `NOTE_TOP_LEVEL_KEYS` | `const NOTE_TOP_LEVEL_KEYS` | `readonly string[]` | reading just the key names, in the order the formatter writes them |
363
- | `NOTE_TOP_LEVEL_KEY_SET` | `const NOTE_TOP_LEVEL_KEY_SET` | `ReadonlySet<string>` | testing whether a top-level key is one the note format declares |
364
- | `SHARED_DATA_FIELDS` | `const SHARED_DATA_FIELDS` | `readonly DataFieldSpec[]` | reading the `data:` keys every type accepts, whatever it is — the art slots legal everywhere |
365
- | `DECLARED_TAGS` | `const DECLARED_TAGS` | — | looking up the tags a note type may declare, grouped |
366
- | `declaredTags` | `declaredTags(type, groups)` | `readonly string[]` | reading the declared tags a note of a type may carry, flattened |
367
- | `applicableTagGroups` | `applicableTagGroups(type, groups)` | `object[]` | reading the declared tag groups that apply to a note type |
368
- | `exclusiveTagGroups` | `exclusiveTagGroups(type, groups)` | `Array<{slot, tags}>` | reading single-valued tag slots declared for a note type |
369
- | `hasTag` | `hasTag(fm, tag)` | `boolean` | checking whether a note carries a given tag, whatever scalar-or-list form it was authored in |
370
- | `isDraftNote` | `isDraftNote(fm)` | `boolean` | checking whether a note is tagged as an unfinished draft |
371
- | `isGmNote` | `isGmNote(fm)` | `boolean` | checking whether a note is restricted to GM-facing output |
372
- | `subTypeCharsetMessage` | `subTypeCharsetMessage(value)` | `string` | building the message for a `subType` outside the address charset |
373
- | `typeCharsetMessage` | `typeCharsetMessage(type)` | `string` | building the message for a `type` outside the address charset |
374
- | `assertVocabularyCharset` | `assertVocabularyCharset(vocabulary, where)` | throws | refusing a vocabulary declaration whose type or subType breaks the address charset |
375
- | `isLegacyDataField` | `isLegacyDataField(type, key)` | `boolean` | testing accepted but ignored transitional affiliation `data.domains` input |
376
- | `dataFields` | `dataFields(type, vocabulary)` | `readonly DataFieldSpec[] \| undefined` | looking up the `data:` keys a note type may carry |
377
- | `subTypes` | `subTypes(type, vocabulary)` | `readonly string[] \| null \| undefined` | looking up the closed `subType` values a note type declares |
356
+ | Export | Signature | Returns | Use it when |
357
+ | ------------------------- | -------------------------------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------- |
358
+ | `DRAFT_TAG` | `const DRAFT_TAG` | — | naming the declared tag that marks a note as unfinished |
359
+ | `GM_TAG` | `const GM_TAG` | — | naming the declared tag that marks a GM-only note |
360
+ | `BEING_ARCHETYPES` | `const BEING_ARCHETYPES` | `Readonly<Record<string, string>>` | looking up the case-sensitive being archetypes and their meanings |
361
+ | `NOTE_VOCABULARY` | `const NOTE_VOCABULARY` | — | looking up, per content type, its `data:` field list and its closed `subType` values |
362
+ | `NOTE_TOP_LEVEL_FIELDS` | `const NOTE_TOP_LEVEL_FIELDS` | `readonly TopLevelFieldSpec[]` | reading the top-level keys a note accepts, in formatted order, with what each one means |
363
+ | `NOTE_TOP_LEVEL_KEYS` | `const NOTE_TOP_LEVEL_KEYS` | `readonly string[]` | reading just the key names, in the order the formatter writes them |
364
+ | `NOTE_TOP_LEVEL_KEY_SET` | `const NOTE_TOP_LEVEL_KEY_SET` | `ReadonlySet<string>` | testing whether a top-level key is one the note format declares |
365
+ | `SHARED_DATA_FIELDS` | `const SHARED_DATA_FIELDS` | `readonly DataFieldSpec[]` | reading the `data:` keys every type accepts, whatever it is — the art slots legal everywhere |
366
+ | `EVENTS_FIELD` | `const EVENTS_FIELD` | `DataFieldSpec` | reading the one `events` declaration that `lore`, `place` and `affiliation` share, with its check |
367
+ | `DECLARED_TAGS` | `const DECLARED_TAGS` | — | looking up the tags a note type may declare, grouped |
368
+ | `declaredTags` | `declaredTags(type, groups)` | `readonly string[]` | reading the declared tags a note of a type may carry, flattened |
369
+ | `applicableTagGroups` | `applicableTagGroups(type, groups)` | `object[]` | reading the declared tag groups that apply to a note type |
370
+ | `exclusiveTagGroups` | `exclusiveTagGroups(type, groups)` | `Array<{slot, tags}>` | reading single-valued tag slots declared for a note type |
371
+ | `hasTag` | `hasTag(fm, tag)` | `boolean` | checking whether a note carries a given tag, whatever scalar-or-list form it was authored in |
372
+ | `isDraftNote` | `isDraftNote(fm)` | `boolean` | checking whether a note is tagged as an unfinished draft |
373
+ | `isGmNote` | `isGmNote(fm)` | `boolean` | checking whether a note is restricted to GM-facing output |
374
+ | `subTypeCharsetMessage` | `subTypeCharsetMessage(value)` | `string` | building the message for a `subType` outside the address charset |
375
+ | `typeCharsetMessage` | `typeCharsetMessage(type)` | `string` | building the message for a `type` outside the address charset |
376
+ | `assertVocabularyCharset` | `assertVocabularyCharset(vocabulary, where)` | throws | refusing a vocabulary declaration whose type or subType breaks the address charset |
377
+ | `dataFields` | `dataFields(type, vocabulary)` | `readonly DataFieldSpec[] \| undefined` | looking up the `data:` keys a note type may carry |
378
+ | `subTypes` | `subTypes(type, vocabulary)` | `readonly string[] \| null \| undefined` | looking up the closed `subType` values a note type declares |
378
379
 
379
380
  ### `engine.infobox`
380
381
 
@@ -392,7 +393,8 @@ The declared infobox: what a note's summary panel holds, decided once and render
392
393
  | `NOTHING_BEYOND_PROFILE` | `const NOTHING_BEYOND_PROFILE` | — | naming what a system holding nothing the note box has not shown says |
393
394
  | `NOTE_BOX_ID` | `const NOTE_BOX_ID` | — | naming the note infobox, which is not a system id |
394
395
  | `NOTE_BOX_TITLE` | `const NOTE_BOX_TITLE` | — | naming the note infobox's heading |
395
- | `NOTE_SECTION_ID` | `const NOTE_SECTION_ID` | — | naming the note infobox's single section |
396
+ | `NOTE_SECTION_ID` | `const NOTE_SECTION_ID` | — | naming the note infobox's profile section |
397
+ | `MEMBERSHIPS_SECTION` | `const MEMBERSHIPS_SECTION` | — | naming the note infobox's `list` section of a being's memberships, one line each |
396
398
  | `NOTE_FIELD_PRESENTATION` | `const NOTE_FIELD_PRESENTATION` | — | looking up a `data:` key's label, the group it composes into, or why it carries no row |
397
399
  | `assertInfoboxSet` | `assertInfoboxSet(boxes, fm, options)` | `readonly object[]`, throws | refusing a page that carries anything but the boxes its type maps to |
398
400
  | `buildInfoboxes` | `buildInfoboxes(fm, options)` | `object[]` | building every box a note carries, against a given set of maps and declarations |
@@ -482,36 +484,35 @@ Every typed note must have a nonempty body. Empty and whitespace-only bodies are
482
484
 
483
485
  What a place is next to (`data.borders`) and reachable from (`data.routes`): the closed sets both draw from, stated once for the lint, the specification and a consumer drawing a map, and the checks that hold a note to them and to the note at the other end.
484
486
 
485
- | Export | Signature | Returns | Use it when |
486
- | ----------------- | ------------------------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------- |
487
- | `RELATION_TYPE` | `const RELATION_TYPE` | `string` | the type a `to` names — the default its `<type>` segment takes and the whole of its accepted set |
488
- | `BEARINGS` | `const BEARINGS` | `readonly string[]` | the eight compass bearings, clockwise from `N` |
489
- | `ROUTE_MODES` | `const ROUTE_MODES` | `readonly string[]` | the modes a route is travelled by — `land`, `boat`, `ship` |
490
- | `TRAVEL_DAYS` | `const TRAVEL_DAYS` | `readonly number[]` | the days markers a route may state, each meaning "about this, under normal conditions" |
491
- | `TERRAIN_MODES` | `const TERRAIN_MODES` | — | the terrain registry, each terrain naming the modes that cross it |
492
- | `TERRAINS` | `const TERRAINS` | `readonly string[]` | the terrain names, in registry order |
493
- | `BORDER_KEYS` | `const BORDER_KEYS` | `readonly string[]` | the keys a `borders` entry carries |
494
- | `ROUTE_KEYS` | `const ROUTE_KEYS` | `readonly string[]` | the keys a `routes` entry carries |
495
- | `oppositeBearing` | `oppositeBearing(bearing)` | `string\|undefined` | the bearing the other end of a relation states, or `undefined` for a value that is not a bearing |
496
- | `checkBorders` | `checkBorders(note, { index })` | `object[]` | linting a place's `borders` — targets, values, once per pair, no parent or child, and reciprocity with the other end |
497
- | `checkRoutes` | `checkRoutes(note, { index })` | `object[]` | linting a place's `routes` — as `checkBorders`, plus `mode`, `days` and `terrain`, once per pair per mode |
487
+ | Export | Signature | Returns | Use it when |
488
+ | ----------------- | ------------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
489
+ | `RELATION_TYPE` | `const RELATION_TYPE` | `string` | the type a `to` names — the default its `<type>` segment takes and the whole of its accepted set |
490
+ | `BEARINGS` | `const BEARINGS` | `readonly string[]` | the eight compass bearings, clockwise from `N` |
491
+ | `ROUTE_MODES` | `const ROUTE_MODES` | `readonly string[]` | the modes a route is travelled by — `land`, `boat`, `ship` |
492
+ | `TRAVEL_DAYS` | `const TRAVEL_DAYS` | `readonly number[]` | the days markers a route may state, each meaning "about this, under normal conditions" |
493
+ | `TERRAIN_MODES` | `const TERRAIN_MODES` | — | the terrain registry, each terrain naming the modes that cross it |
494
+ | `TERRAINS` | `const TERRAINS` | `readonly string[]` | the terrain names, in registry order |
495
+ | `BORDER_FIELDS` | `const BORDER_FIELDS` | `readonly object[]` | the keys a `borders` entry carries, as inner-key declarations — name, kind, shape and whether it is required |
496
+ | `ROUTE_FIELDS` | `const ROUTE_FIELDS` | `readonly object[]` | the keys a `routes` entry carries, as inner-key declarations |
497
+ | `BORDER_KEYS` | `const BORDER_KEYS` | `readonly string[]` | the keys a `borders` entry carries |
498
+ | `ROUTE_KEYS` | `const ROUTE_KEYS` | `readonly string[]` | the keys a `routes` entry carries |
499
+ | `oppositeBearing` | `oppositeBearing(bearing)` | `string\|undefined` | the bearing the other end of a relation states, or `undefined` for a value that is not a bearing |
500
+ | `checkBorders` | `checkBorders(note, { index })` | `object[]` | linting what a place's `borders` mean — targets, bearings, once per pair, no parent or child, and reciprocity; an entry's keys and shape are the frontmatter lint's |
501
+ | `checkRoutes` | `checkRoutes(note, { index })` | `object[]` | linting what a place's `routes` mean — as `checkBorders`, plus `mode`, `days` and `terrain`, once per pair per mode |
498
502
 
499
503
  ### `engine.holdings`
500
504
 
501
- What lies within a place and which affiliation explicitly governs it — read off `data.parents` and resolved explicit `data.government` across this package and every fetched index, inverted into the `contains`, `governed_by` and `governed_places` lists the site build writes — and the population-based government advisory `package-build lint` runs on a place.
505
+ What lies within a place and which affiliation explicitly governs it — read off `data.parents` and resolved explicit `data.government` across this package and every fetched index, inverted into the lists a note's generated **Within**, **Governed by** and **Governed places** sections show — and the population-based government advisory `package-build lint` runs on a place.
502
506
 
503
- | Export | Signature | Returns | Use it when |
504
- | ---------------------- | --------------------------------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
505
- | `HOLDINGS_KEYS` | `const HOLDINGS_KEYS` | `readonly string[]` | derived `contains`, `governed_by`, `governed_places` and retired `held_by`/`holdings` keys removed from authored page metadata |
506
- | `HELD_SUBTYPES` | `const HELD_SUBTYPES` | `readonly string[]` | deprecated historical tenure subtypes; government checks apply to every place subtype |
507
- | `holdingsNode` | `holdingsNode(fm, { title, url, package, system })` | `HoldingsNode\|null` | reading a local note as a node of the derivation, or `null` for one that is neither a place nor an affiliation |
508
- | `foreignHoldingsNodes` | `foreignHoldingsNodes(foreignIndex)` | `HoldingsNode[]` | reading a fetched index's places and affiliations as nodes |
509
- | `holdingsPages` | `holdingsPages(nodes, { governmentNodes })` | `Map<string, Holdings>` | inverting `parents` and resolved explicit `government` into each page's sorted lists, keyed by URL, for every page with at least one entry |
510
- | `shortcodesOf` | `shortcodesOf(value)` | `string[]` | the shortcodes a `parents` value names — bare or qualified Addresses — empties dropped and repeats collapsed |
511
- | `checkGovernment` | `checkGovernment(note)` | `object[]` | warning at `data.population` for positive population with no own `data.government` key; explicit null means anarchy |
512
- | `checkHeld` | `checkHeld(note, { index })` | `object[]` | deprecated compatibility wrapper for `checkGovernment`; holdings do not determine government |
507
+ | Export | Signature | Returns | Use it when |
508
+ | ---------------------- | -------------------------------------------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
509
+ | `holdingsNode` | `holdingsNode(fm, { title, url, package, system, canonical })` | `HoldingsNode\|null` | reading a local note as a node of the derivation, or `null` for one that is neither a place nor an affiliation |
510
+ | `foreignHoldingsNodes` | `foreignHoldingsNodes(foreignIndex)` | `HoldingsNode[]` | reading a fetched index's places and affiliations as nodes |
511
+ | `holdingsPages` | `holdingsPages(nodes, { governmentNodes })` | `Map<string, Holdings>` | inverting `parents` and resolved explicit `government` into each node's sorted lists, keyed by its `url`, for every node with a `url` and an entry |
512
+ | `shortcodesOf` | `shortcodesOf(value)` | `string[]` | the shortcodes a `parents` value names — bare or qualified Addresses — empties dropped and repeats collapsed |
513
+ | `checkGovernment` | `checkGovernment(note)` | `object[]` | warning at `data.population` for positive population with no own `data.government` key; explicit null means anarchy |
513
514
 
514
- Government-only supplemental records passed in `holdingsPages` options include public local stubs in the reverse lists without adding them to the geographical graph. Published nodes retain precedence; stubs without URLs render as plain text.
515
+ An entry carries the listed note's `title`, its `address` in the `note` system, its `type` and `subType`, and its `url` where the note has one. A node with no `url` — a stub — is listed by others and carries no list of its own. Records passed as `governmentNodes` take part in government alone, never in geography.
515
516
 
516
517
  ### `engine.populations`
517
518
 
@@ -588,12 +589,12 @@ The drawings of `package-build map` as DOT text, sharing one style table: shape,
588
589
 
589
590
  ### `engine.mapGraphviz`
590
591
 
591
- The npm-installed Graphviz runtime draws SVG maps and supplies the plain positions used by Foundry itinerary pins. PNG backgrounds are rasterized from the same SVG layout. The `.dot` source stays beside each rendering.
592
+ The npm-installed Graphviz runtime draws SVG maps. The `.dot` source stays beside each rendering.
592
593
 
593
- | Export | Signature | Returns | Use it when |
594
- | ------------------ | ----------------------------------------------------------- | ------------------- | ------------------------------------------------------ |
595
- | `GRAPHVIZ_ENGINES` | `const GRAPHVIZ_ENGINES` | `readonly string[]` | choosing `dot`, `twopi`, or `neato` |
596
- | `renderDot` | `renderDot(dotPath, outPath, { engine, format, nop, dpi })` | `{warnings}` | rendering a DOT source to SVG, plain positions, or PNG |
594
+ | Export | Signature | Returns | Use it when |
595
+ | ------------------ | ---------------------------------------------- | ------------------- | ----------------------------------- |
596
+ | `GRAPHVIZ_ENGINES` | `const GRAPHVIZ_ENGINES` | `readonly string[]` | choosing `dot`, `twopi`, or `neato` |
597
+ | `renderDot` | `renderDot(dotPath, outPath, { engine, nop })` | `{warnings}` | rendering a DOT source to SVG |
597
598
 
598
599
  ### `engine.mapBuild`
599
600
 
@@ -608,13 +609,14 @@ The npm-installed Graphviz runtime draws SVG maps and supplies the plain positio
608
609
 
609
610
  ### `engine.siteMaps`
610
611
 
611
- The map from each place, drawn for the site: `package-build site` draws the map from every place of this package that states, or is named in, a border or a route — with the site's base, so every name links through it — and the page writer lays each drawing beside its page as `from-<shortcode>.svg` and names it in the front matter as `map`. `site.maps: false` draws none.
612
+ The map from each place, drawn for the site: `package-build site` draws the map from every place of this package given a **From here** section — with the site's base, so every name links through it — and sets each drawing inline in that section, where its place names stay links. `site.maps: false` gives no place the section, and nothing is drawn.
612
613
 
613
- | Export | Signature | Returns | Use it when |
614
- | -------------- | ------------------------------------------------------- | ------------------ | --------------------------------------------------------------------------------------------------------------- |
615
- | `SITE_MAP_DIR` | `const SITE_MAP_DIR` | `string` | where the site build draws below a package's root, `build/map/site` |
616
- | `inlineSvg` | `inlineSvg(svg)` | `string` | rewriting a GraphViz SVG for inlining — no prologue, no comment, no `xlink:`, the root sized by `viewBox` alone |
617
- | `drawSiteMaps` | `drawSiteMaps({ records, foreignIndex, config, base })` | `{maps, findings}` | drawing the map from every related place of this package, keyed by the URL of the page that carries it |
614
+ | Export | Signature | Returns | Use it when |
615
+ | --------------------- | ------------------------------------------------------- | ------------------ | --------------------------------------------------------------------------------------------------------------- |
616
+ | `SITE_MAP_DIR` | `const SITE_MAP_DIR` | `string` | where the site build draws below a package's root, `build/map/site` |
617
+ | `inlineSvg` | `inlineSvg(svg)` | `string` | rewriting a GraphViz SVG for inlining — no prologue, no comment, no `xlink:`, the root sized by `viewBox` alone |
618
+ | `drawSiteMaps` | `drawSiteMaps({ records, foreignIndex, config, base })` | `{maps, findings}` | drawing the map from every place given a **From here** section, keyed by the file name the section names |
619
+ | `inlineDrawingFigure` | `inlineDrawingFigure(svg, alt)` | `string` | the one HTML block the website sets an inline drawing in, with no blank line to end it early |
618
620
 
619
621
  ### `engine.systems`
620
622
 
@@ -658,7 +660,7 @@ The neutral day spelling is `<year>.<day>[:HHMMSS]`. The pure conversion functio
658
660
 
659
661
  ### `engine.noteDates`
660
662
 
661
- A date on a note is one authored scalar. `<year>[.<day>[:HHMMSS]]` names a calendar-neutral year, day, or second; `datefrom vrcal 23 Taranis 326 VR` names a calendar, a named month, and an era. Year and day values span their written interval; a clock time identifies a second. Either form may begin with `~` for uncertainty beyond that interval. The `approximate` field records that explicit marker, while `precision` and `seconds` describe the interval or time. A resolved date carries a canonical year, span, and sort key; a neutral year has no `canonicalDay`, while day-precision dates have one. Print `prose ?? text`, order on `sort`, and do arithmetic on `canonicalYear`. The literal `unknown` has no sort key or canonical year. Year `0` is accepted only where a caller passes `allowZeroYear` — a `lore` event's `when` — and means "this day, every year": the value carries no `canonicalYear` and no `sort`. `resolvedDateFields` supplies identical derived records to JSONL and generated page frontmatter, including a `lore` note's `data.events`, each entry's `recurs` and computed `next`.
663
+ A date on a note is one authored scalar. `<year>[.<day>[:HHMMSS]]` names a calendar-neutral year, day, or second; `datefrom vrcal 23 Taranis 326 VR` names a calendar, a named month, and an era. Year and day values span their written interval; a clock time identifies a second. Either form may begin with `~` for uncertainty beyond that interval. The `approximate` field records that explicit marker, while `precision` and `seconds` describe the interval or time. A resolved date carries a canonical year, span, and sort key; a neutral year has no `canonicalDay`, while day-precision dates have one. Print `prose ?? text`, order on `sort`, and do arithmetic on `canonicalYear`. The literal `unknown` has no sort key or canonical year. Year `0` is accepted only where a caller passes `allowZeroYear` — an event's `when` — and means "this day, every year": the value carries no `canonicalYear` and no `sort`. `resolvedDateFields` supplies the derived records the JSONL carries, including each `data.events` entry's dates, `recurs` and computed `next`; generated page front matter carries the same records for every date except an event's.
662
664
 
663
665
  | Export | Signature | Returns | Use it when |
664
666
  | ----------------------- | ------------------------------------------------------------- | -------------------------------------------------- | -------------------------------------------------------------- |
@@ -725,22 +727,23 @@ The corpus registry anchors each calendar's year 1, day 1 to its canonical `data
725
727
 
726
728
  A calendar is a `lore` note with `subType: calendar`, declaring the months it keeps, the weekdays it names, the seasons it marks and the eras it counts years in. How long the year is, how the day divides and how the moon moves are facts about the **world**, written on its `place` note and its moon's, and no calendar may restate them — which is why the months summing to the world's year is the only arithmetic a calendar note is held to. One definition is emitted per calendar, in array shape: Foundry core prunes the keys outside its schema, and Calendaria converts the arrays to its own keyed collections.
727
729
 
728
- | Export | Signature | Returns | Use it when |
729
- | --------------------------- | ----------------------------------------------------- | ------------------------------------------ | --------------------------------------------------------------------------- |
730
- | `CALENDAR_SUBTYPE` | `const CALENDAR_SUBTYPE` | — | naming the `lore` subType whose notes are calendars |
731
- | `INVARIANT_SUBTYPES` | `const INVARIANT_SUBTYPES` | — | naming the `place` subTypes a world fact may be written on |
732
- | `CALENDAR_FIELDS` | `const CALENDAR_FIELDS` | — | reading the closed list of what a calendar note may declare |
733
- | `CALENDAR_DATE_FORMAT_KEYS` | `const CALENDAR_DATE_FORMAT_KEYS` | — | reading the supported Calendaria display slots |
734
- | `CALENDAR_FORMAT_TOKENS` | `const CALENDAR_FORMAT_TOKENS` | — | checking bare date tokens in a format string |
735
- | `INVARIANT_FIELDS` | `const INVARIANT_FIELDS` | — | reading the closed list of what a body may declare about itself |
736
- | `checkCalendarNote` | `checkCalendarNote(note, opts)` | `object[]` — findings | holding a `lore` note to the family and to the year the world keeps |
737
- | `checkCalendarDateFormats` | `checkCalendarDateFormats(note)` | `object[]` — findings | checking named patterns and the readable default |
738
- | `checkWorldFacts` | `checkWorldFacts(note, opts)` | `object[]` — findings | holding a `place` note's world facts to one body, one year and one moon |
739
- | `worldInvariants` | `worldInvariants(index)` | `{year, present, moon, body, moonName, …}` | reading the year, the present and the moon a package's own notes state |
740
- | `quarterDays` | `quarterDays(daysPerYear)` | `number[]` — four days of the year | asking which days the year turns on |
741
- | `compileCalendar` | `compileCalendar({note, invariants, contentPackage})` | `object` — the definition | building the one object both a core consumer and Calendaria read |
742
- | `compileCalendars` | `compileCalendars(index, opts)` | `{calendars, invariants}` | building every calendar a package declares, or none where it states no year |
743
- | `calendariaEnvelope` | `calendariaEnvelope(definition, opts)` | `object` — the import envelope | wrapping a definition for a hand import through Calendaria's settings |
730
+ | Export | Signature | Returns | Use it when |
731
+ | --------------------------- | ----------------------------------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------- |
732
+ | `CALENDAR_SUBTYPE` | `const CALENDAR_SUBTYPE` | — | naming the `lore` subType whose notes are calendars |
733
+ | `INVARIANT_SUBTYPES` | `const INVARIANT_SUBTYPES` | — | naming the `place` subTypes a world fact may be written on |
734
+ | `CALENDAR_FIELDS` | `const CALENDAR_FIELDS` | — | reading the closed list of what a calendar note may declare |
735
+ | `CALENDAR_ENTRY_FIELDS` | `const CALENDAR_ENTRY_FIELDS` | — | reading the keys one entry of each calendar list takes, as inner-key declarations |
736
+ | `CALENDAR_DATE_FORMAT_KEYS` | `const CALENDAR_DATE_FORMAT_KEYS` | — | reading the supported Calendaria display slots |
737
+ | `CALENDAR_FORMAT_TOKENS` | `const CALENDAR_FORMAT_TOKENS` | — | checking bare date tokens in a format string |
738
+ | `INVARIANT_FIELDS` | `const INVARIANT_FIELDS` | — | reading the closed list of what a body may declare about itself |
739
+ | `checkCalendarNote` | `checkCalendarNote(note, opts)` | `object[]` — findings | holding a `lore` note to the family and to the year the world keeps |
740
+ | `checkCalendarDateFormats` | `checkCalendarDateFormats(note)` | `object[]` — findings | checking named patterns and the readable default |
741
+ | `checkWorldFacts` | `checkWorldFacts(note, opts)` | `object[]` — findings | holding a `place` note's world facts to one body, one year and one moon |
742
+ | `worldInvariants` | `worldInvariants(index)` | `{year, present, moon, body, moonName, …}` | reading the year, the present and the moon a package's own notes state |
743
+ | `quarterDays` | `quarterDays(daysPerYear)` | `number[]` — four days of the year | asking which days the year turns on |
744
+ | `compileCalendar` | `compileCalendar({note, invariants, contentPackage})` | `object` — the definition | building the one object both a core consumer and Calendaria read |
745
+ | `compileCalendars` | `compileCalendars(index, opts)` | `{calendars, invariants}` | building every calendar a package declares, or none where it states no year |
746
+ | `calendariaEnvelope` | `calendariaEnvelope(definition, opts)` | `object` — the import envelope | wrapping a definition for a hand import through Calendaria's settings |
744
747
 
745
748
  ### `engine.calendarArtifacts`
746
749
 
@@ -878,7 +881,7 @@ Emitting this package's content index. Every content build already walks the who
878
881
 
879
882
  | Export | Signature | Returns | Use it when |
880
883
  | --------------------- | -------------------------------- | -------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
881
- | `collectAnchors` | `collectAnchors(body, bodyLine)` | `Array<{slug: string, line: number}>` | reading a note body's anchors, shared with the link checker and every build that emits a link |
884
+ | `collectAnchors` | `collectAnchors(body, bodyLine)` | `Array<{slug: string, line: number, kind: string}>` | reading a note body's anchors, each with its kind, shared with the link checker and every build that emits a link |
882
885
  | `DERIVED_KEYS` | `const DERIVED_KEYS` | — | reading which keys the content index adds to a record, and which a note therefore may not author itself |
883
886
  | `noteFile` | `noteFile(contentBase, record)` | `string` — the note's absolute path | composing an index record's `file.path` (recorded relative, for a byte-stable artifact) back into an openable absolute path |
884
887
  | `authoredFrontmatter` | `authoredFrontmatter(record)` | `Record<string, any>` — the frontmatter without `DERIVED_KEYS` | reading back exactly what a note authored from its index record, so a pass can lint or compile from the index without reasoning about derived fields as if the author wrote them |
@@ -947,22 +950,22 @@ pages and link findings, while `collectHomepages` gathers package homepages.
947
950
  `writeHomepages` places those homepages at each package's site root. The same
948
951
  content tree can also compile into Foundry compendium packs.
949
952
 
950
- | Export | Signature | Returns | Use it when |
951
- | --------------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
952
- | `collectContentPages` | `function collectContentPages(contentBase, ctx)` | `{{pages: object[], addressFindings: object[], fmLinkFindings: object[]}}` | The content tree's pages, and what could not be addressed. |
953
- | `collectHomepages` | `function collectHomepages(contentBase, ctx)` | `{{pages: object[], addressFindings: object[]}}` The homepage notes, in walk order, and the ones among them that could not be addressed. | The package's homepage notes — the authored page at `/<contentPackage>/`. |
954
- | `writeHomepages` | `function writeHomepages(outRoot, pages, config)` | {number} How many pages were written. | Writes each homepage as the package root's `_index.md`. |
955
- | `siteGates` | `function siteGates(pages, findings,` | {object} The gate results and, when they pass, the built index. | The integrity gates a site build runs before it writes anything. |
956
- | `emptyGates` | `function emptyGates()` | {object} An all-clear gate result. | The gate result of a build that ran none of them. |
957
- | `gatesFailed` | `function gatesFailed(gates)` | — | Whether any gate produced a finding. |
958
- | `tableUniverse` | `function tableUniverse(pages)` | {Map<string, object[]>} Package → the notes it may tabulate. | The universe a generated table searches, grouped by package. |
959
- | `pageFrontmatter` | `function pageFrontmatter(page,` | {object} The frontmatter to write. | The frontmatter a page publishes with. |
960
- | `pageDestination` | `function pageDestination(page, { bundle })` | — | Where a page is written, relative to the output root: flat, or as a leaf bundle when it carries a file beside itself. |
961
- | `renderSitePage` | `renderSitePage(page, options)` | `{body, data, resolved, tableErrors, secretErrors, wikiErrors, imageErrors}` | Transform one page with the same passes the site writer uses. |
962
- | `renderPages` | `function renderPages(pages, options)` | `{{written: number, byKind: Record<string, number>, tableErrors: object[], wikiErrors: object[]}}` | Renders and writes every page. |
963
- | `resolveSitePass` | `function resolveSitePass(name, options)` | `{{beforeLinks?: Function}}` The bundle. | Resolves `site.pass` to its bundle. |
964
- | `sitePageDecorator` | `sitePageDecorator(config, index)` | Function | Add the site's infobox and being metadata to a rendered page. |
965
- | `buildSite` | `buildSite({ config, sqlTables })` | `{{gates: object, stats: object\|null, tableErrors: object[], wikiErrors: object[], mapFindings: object[], manifests: object\|null}}` | Builds a Hugo content tree from a content tree, and reports what it found. |
953
+ | Export | Signature | Returns | Use it when |
954
+ | --------------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
955
+ | `collectContentPages` | `function collectContentPages(contentBase, ctx)` | `{{pages: object[], addressFindings: object[], fmLinkFindings: object[]}}` | The content tree's pages, and what could not be addressed. |
956
+ | `collectHomepages` | `function collectHomepages(contentBase, ctx)` | `{{pages: object[], addressFindings: object[]}}` The homepage notes, in walk order, and the ones among them that could not be addressed. | The package's homepage notes — the authored page at `/<contentPackage>/`. |
957
+ | `writeHomepages` | `function writeHomepages(outRoot, pages, config)` | {number} How many pages were written. | Writes each homepage as the package root's `_index.md`. |
958
+ | `siteGates` | `function siteGates(pages, findings,` | {object} The gate results and, when they pass, the built index. | The integrity gates a site build runs before it writes anything. |
959
+ | `emptyGates` | `function emptyGates()` | {object} An all-clear gate result. | The gate result of a build that ran none of them. |
960
+ | `gatesFailed` | `function gatesFailed(gates)` | — | Whether any gate produced a finding. |
961
+ | `tableUniverse` | `function tableUniverse(pages)` | {Map<string, object[]>} Package → the notes it may tabulate. | The universe a generated table searches, grouped by package. |
962
+ | `pageFrontmatter` | `function pageFrontmatter(page,` | {object} The frontmatter to write. | The frontmatter a page publishes with. |
963
+ | `pageDestination` | `function pageDestination(page)` | — | Where a page is written, relative to the output root: `<slug>.md`, flat under the mount. |
964
+ | `renderSitePage` | `renderSitePage(page, options)` | `{body, data, resolved, tableErrors, secretErrors, wikiErrors, imageErrors}` | Transform one page with the same passes the site writer uses. |
965
+ | `renderPages` | `function renderPages(pages, options)` | `{{written: number, byKind: Record<string, number>, tableErrors: object[], wikiErrors: object[]}}` | Renders and writes every page. |
966
+ | `resolveSitePass` | `function resolveSitePass(name, options)` | `{{beforeLinks?: Function}}` The bundle. | Resolves `site.pass` to its bundle. |
967
+ | `sitePageDecorator` | `sitePageDecorator(config, index)` | Function | Add the site's infobox and being metadata to a rendered page. |
968
+ | `buildSite` | `buildSite({ config, sqlTables })` | `{{gates: object, stats: object\|null, tableErrors: object[], wikiErrors: object[], mapFindings: object[], manifests: object\|null}}` | Builds a Hugo content tree from a content tree, and reports what it found. |
966
969
 
967
970
  ### `engine.sitePreview`
968
971
 
@@ -1226,19 +1229,20 @@ Wikilink resolution for the pack compilers. Content notes link to one another wi
1226
1229
 
1227
1230
  What a `[[…]]` **is**, before anything decides where it points. One authored link compiles to two different addresses — a Foundry `@UUID` enricher for the packs, a URL for the web — and those two destinations are the _only_ thing that legitimately differs. The syntax is the author's, and it is the same syntax whichever build is reading it.
1228
1231
 
1229
- | Export | Signature | Returns | Use it when |
1230
- | -------------------------- | ---------------------------------------------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------- |
1231
- | `WIKILINK` | `const WIKILINK` | — | A wikilink, as authored. |
1232
- | `parseWikilink` | `function parseWikilink(rawInner)` | {ParsedWikilink} The parts, each trimmed. | Split a wikilink's interior into its parts. |
1233
- | `readWikilink` | `function readWikilink(inner, context)` | Typed target or literal target with diagnostic source. | Parse a link target using complete builder Address context. |
1234
- | `authoredLabel` | `authoredLabel({ display })` | {string\|null} The label, or `null` when there is none to show. | The label an author actually supplied, or `null` when they supplied none. |
1235
- | `unlabelledLinkMessage` | `function unlabelledLinkMessage(target)` | {string} The message, unpunctuated at the end as a finding is. | What an author writing an unlabelled link is told, in one place. |
1236
- | `LINK_FINDING_REASONS` | `const LINK_FINDING_REASONS` | — | Every way a link can fail, named once for all three resolvers. |
1237
- | `unresolvedAddressMessage` | `function unresolvedAddressMessage(target)` | {string} The message, unpunctuated at the end as a finding is. | What an author writing an address that resolves to nothing is told. |
1238
- | `stubAddressMessage` | `function stubAddressMessage(target, file)` | {string} The message, unpunctuated at the end as a finding is. | What an author linking to a stub is told, naming the file to open. |
1239
- | `ambiguousAddressMessage` | `function ambiguousAddressMessage(target, packages` | {string} The message. | What an author writing a short address more than one package publishes is told. |
1240
- | `linkFindingMessage` | `linkFindingMessage({ reason, target, packages, anchor })` | {string} The message. | The message for one link finding, whichever resolver found it. |
1241
- | `isSamePage` | `isSamePage({ target, anchor })` | {boolean} True when the link is same-page. | Whether a parsed link addresses a section of the page it is written on. |
1232
+ | Export | Signature | Returns | Use it when |
1233
+ | -------------------------- | ---------------------------------------------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
1234
+ | `WIKILINK` | `const WIKILINK` | — | A wikilink, as authored. |
1235
+ | `parseWikilink` | `function parseWikilink(rawInner)` | {ParsedWikilink} The parts, each trimmed. | Split a wikilink's interior into its parts. |
1236
+ | `readWikilink` | `function readWikilink(inner, context)` | Typed target or literal target with diagnostic source. | Parse a link target using complete builder Address context. |
1237
+ | `authoredLabel` | `authoredLabel({ display })` | {string\|null} The label, or `null` when there is none to show. | The label an author actually supplied, or `null` when they supplied none. |
1238
+ | `unlabelledLinkMessage` | `function unlabelledLinkMessage(target)` | {string} The message, unpunctuated at the end as a finding is. | What an author writing an unlabelled link is told, in one place. |
1239
+ | `LINK_FINDING_REASONS` | `const LINK_FINDING_REASONS` | — | Every way a link can fail, named once for all three resolvers. |
1240
+ | `unresolvedAddressMessage` | `function unresolvedAddressMessage(target)` | {string} The message, unpunctuated at the end as a finding is. | What an author writing an address that resolves to nothing is told. |
1241
+ | `stubAddressMessage` | `function stubAddressMessage(target, file)` | {string} The message, unpunctuated at the end as a finding is. | What an author linking to a stub is told, naming the file to open. |
1242
+ | `ambiguousAddressMessage` | `function ambiguousAddressMessage(target, packages` | {string} The message. | What an author writing a short address more than one package publishes is told. |
1243
+ | `linkFindingMessage` | `linkFindingMessage({ reason, target, packages, anchor })` | {string} The message. | The message for one link finding, whichever resolver found it. |
1244
+ | `isEventAnchor` | `isEventAnchor(hit, anchor)` | {boolean} Whether it is an event. | Whether the anchor a wikilink names is one of its target's events, which a wikilink may not name. |
1245
+ | `isSamePage` | `isSamePage({ target, anchor })` | {boolean} True when the link is same-page. | Whether a parsed link addresses a section of the page it is written on. |
1242
1246
 
1243
1247
  ### `engine.siteIndex`
1244
1248
 
@@ -1348,42 +1352,21 @@ Macros pack compiler — produces JSON pack files for the "macros" Foundry compe
1348
1352
  | `buildMacroEntry` | `function buildMacroEntry(fm,` | {MacroDocument} The Macro document. | The compendium envelope for one Macro. |
1349
1353
  | `Macros` | `class Macros extends BasePackCompiler` | — | Macros pack compiler. |
1350
1354
 
1351
- ### `engine.mapNotes`
1352
-
1353
- **Map notes** — the markdown → Foundry `Scene` translation. A map note carries an _essence_: a curated, hand-owned subset of what a Scene record holds, exactly as a weapon note carries a weapon's essence rather than an Item's schema. Everything a Scene needs and nobody should have to author — the canvas defaults, the embedded `Level`, every derived region field — is synthesised here.
1354
-
1355
- | Export | Signature | Returns | Use it when |
1356
- | ------------------------------ | ----------------------------------------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
1357
- | `isMapType` | `function isMapType(type)` | {boolean} True for a map type. | Whether a content note's type compiles into a Scene. |
1358
- | `MAP_SUBTYPE_PROFILES` | `const MAP_SUBTYPE_PROFILES` | — | Per-subtype canvas defaults, emitted **explicitly** on every scene. |
1359
- | `mapProfile` | `function mapProfile(subType)` | {object} The profile from {@link MAP_SUBTYPE_PROFILES}. | The canvas profile for a map subType. |
1360
- | `DEFAULT_LEVEL_ID` | `const DEFAULT_LEVEL_ID` | — | Foundry's own id for the level a scene is created with (`Scene.metadata.defaultLevelId`). |
1361
- | `regionDocId` | `function regionDocId(sceneId, key, pinned)` | {string} A 16-character Foundry id. | The id of one region within its scene. |
1362
- | `behaviorDocId` | `function behaviorDocId(regionId, key, pinned)` | {string} A 16-character Foundry id. | The id of one behaviour within its region. |
1363
- | `regionColor` | `function regionColor(key)` | {string} A CSS hex colour. | A region's highlight colour, derived from its key. |
1364
- | `assertPixelGeometry` | `function assertPixelGeometry(coords, geom)` | — | Reject geometry authored in grid squares where pixels belong. |
1365
- | `assertGridLocation` | `function assertGridLocation(at, geom)` | — | Reject a map pin authored in pixels where grid squares belong. |
1366
- | `wallRestrictions` | `function wallRestrictions(spec, label)` | `{{move: number, sight: number, light: number, sound: number}}` The Wall restriction fields. | Compile a wall's `blocks:` / `limits:` lists into Foundry's four numeric restriction fields. |
1367
- | `buildShape` | `function buildShape(spec, geom)` | {object} The Foundry shape record. | Compile one authored shape into a Foundry shape record. |
1368
- | `REGION_BEHAVIOR_TYPES` | `const REGION_BEHAVIOR_TYPES` | — | The behaviour types a map note may carry (v1). |
1369
- | `BANNED_REGION_BEHAVIOR_TYPES` | `const BANNED_REGION_BEHAVIOR_TYPES` | — | Behaviour types a map note may **never** carry, and why. |
1370
- | `buildScene` | `function buildScene(fm, ctx)` | {object} The Scene document, keyed for the pack. | Compile a map note into a Scene document, embedded documents and all. |
1371
- | `buildLevel` | `function buildLevel(sohl, sceneId, img` | {object} The Level document, keyed for the pack. | Synthesise the scene's single embedded Level from `img:` / `overlay:`. |
1372
- | `buildWalls` | `function buildWalls(sohl, geom, ctx)` | {object[]} The Wall documents. | Compile the `walls:` and `doors:` blocks into Wall documents. |
1373
- | `buildLights` | `function buildLights(sohl, geom, ctx)` | {object[]} The AmbientLight documents. | Compile the `lights:` block into AmbientLight documents. |
1374
- | `buildTiles` | `function buildTiles(sohl, geom, ctx)` | {object[]} The Tile documents. | Compile the `tiles:` block into Tile documents. |
1375
- | `buildSounds` | `function buildSounds(sohl, geom, ctx)` | {object[]} The AmbientSound documents. | Compile the `sounds:` block into AmbientSound documents. |
1376
- | `buildLocations` | `function buildLocations(sohl, geom, ctx)` | {object[]} The Note documents. | Compile the `locations:` block into Note documents — the map pins. |
1377
- | `buildRegions` | `function buildRegions(sohl, geom, ctx)` | {object[]} The Region documents. | Compile the `regions:` block into Region documents with their behaviours. |
1355
+ ### `engine.exportedScene`
1356
+
1357
+ An exported Foundry Scene's compile. A map note carries its Scene as exported from Foundry at `data.scene`; this passes it through, applying `data.fixup`, keying each embedded document that carries an `_id`, and binding pins marked `#anchor` to the note's own journal pages. Nothing else inside the Scene is checked.
1358
+
1359
+ | Export | Signature | Returns | Use it when |
1360
+ | -------------------- | -------------------------------------------------------------------------------------- | ---------------------------------- | ---------------------------------------------------- |
1361
+ | `buildExportedScene` | `function buildExportedScene(fm, markdown, { journalEntryId, stats, resolveAddress })` | {object} The keyed Scene document. | Compile a Foundry Scene export into a pack document. |
1378
1362
 
1379
1363
  ### `engine.scenes`
1380
1364
 
1381
- Scenes pack compiler — map notes in `assets/content/` → Foundry `Scene` documents, and the `Adventure` bundles that make their references resolve. The translation itself lives in the framework-free `map-notes.mjs`; this module is the pass that walks the tree, resolves what one note says about another, and writes the JSON the compendium CLI compiles.
1365
+ Scenes pack compiler — map notes in `assets/content/` → Foundry `Scene` documents, and the `Adventure` bundles that make their pins resolve. Each map note's Scene is the one it exports from Foundry, compiled by `engine.exportedScene`; the build never constructs a Scene.
1382
1366
 
1383
- | Export | Signature | Returns | Use it when |
1384
- | ------------------------- | -------------------------------------------- | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1385
- | `collectKnownActionNames` | `function collectKnownActionNames(repoRoot)` | {Set<string>} The known action names. | Every SoHL action name this build knows about, for the `action:` warning on a region trigger. |
1386
- | `Scenes` | `class Scenes extends BasePackCompiler` | — | not called directly — imported and driven by `engine/generate.mjs` as the "scenes" pack compiler; walks the tree, resolves cross-scene references, and writes the JSON the compendium CLI compiles |
1367
+ | Export | Signature | Returns | Use it when |
1368
+ | -------- | --------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
1369
+ | `Scenes` | `class Scenes extends BasePackCompiler` | — | not called directly — imported and driven by `engine/generate.mjs` as the "scenes" pack compiler; compiles each exported Scene and bundles pinned places |
1387
1370
 
1388
1371
  ### `engine.bundleNotes`
1389
1372
 
@@ -1970,7 +1953,7 @@ Not a JavaScript module — this subpath entry exists so tooling (bundlers, `imp
1970
1953
 
1971
1954
  ## Markup parsing modules
1972
1955
 
1973
- The engine wildcard subpath also exposes the body parsers below. Historical figure API names now operate on leading captions; `:::figure` is removed.
1956
+ The engine wildcard subpath also exposes the body parsers below. Their figure exports operate on leading captions.
1974
1957
 
1975
1958
  | Module | Exports | Contract |
1976
1959
  | ---------------------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -36,7 +36,7 @@ license: CC-BY-SA-4.0
36
36
  role: portrait
37
37
  ```
38
38
 
39
- **A hero image is 1792×768.** `data.banner` fills one fixed strip wherever it is drawn, so every banner is cut to that size and a picture of any other size is a finding naming both sizes — resize the picture to match. That is the one size any art field requires. A map's `bgImage` sets its own scene's dimensions, so that asks nothing of a picture's dimensions either.
39
+ **A hero image is 1792×768.** `data.banner` fills one fixed strip wherever it is drawn, so every banner is cut to that size and a picture of any other size is a finding naming both sizes — resize the picture to match. That is the one size any art field requires.
40
40
 
41
41
  `data.banner` reads in one of three states:
42
42
 
@@ -88,16 +88,20 @@ In prose, `{{dateformat "commoncal" data.born}}` prints a date in the chosen cal
88
88
 
89
89
  ## Write a recurring date
90
90
 
91
- A `lore` note states its dated occurrences under `data.events`, a list — a note may record a founding once and an annual festival beside it. Each entry is `{ when, until?, recurs? }`, with `when` the occurrence's anchor and first instance:
91
+ A `lore`, `place` or `affiliation` note states its dated occurrences under `data.events`, a list — a note may record a founding once and an annual festival beside it. Each entry carries `when`, the occurrence's anchor and first instance, and optionally `until` and `recurs`; it also states a `summary`, and a note holding several gives each an `id`. The [Events reference](../reference/format-details.md#events) lists every key an entry takes.
92
92
 
93
93
  ```yaml
94
94
  data:
95
95
  events:
96
- - when: 412.1
96
+ - id: founders
97
+ when: "412.1"
97
98
  recurs: { every: 1 }
98
- - when: 689.5
99
- until: 1203.9
99
+ summary: The city keeps the day of its founding.
100
+ - id: conjunction
101
+ when: "689.5"
102
+ until: "1203.9"
100
103
  recurs: { every: 514 }
104
+ summary: The great conjunction is observed from the temple roof.
101
105
  ```
102
106
 
103
107
  The first entry is annual, with no end. The second recurs every five hundred fourteen years and stopped after canonical year 1203; `recurs.every` always counts whole years on the canonical axis. In place of a period, `recurs.on` lists the dates somebody actually recorded, strictly increasing and each later than `when`:
@@ -105,12 +109,13 @@ The first entry is annual, with no end. The second recurs every five hundred fou
105
109
  ```yaml
106
110
  data:
107
111
  events:
108
- - when: 326.1
112
+ - when: "326.1"
109
113
  recurs:
110
114
  on: ["412.1", "689.5"]
115
+ summary: The comet is recorded over the harbor.
111
116
  ```
112
117
 
113
- A build computes the next occurrence against the world's declared present the way it computes a being's age against it, and publishes it on the web page, in the content index, and in the infobox.
118
+ A build resolves each occurrence on the canonical axis, and the content index carries the result under `resolvedDates.events`.
114
119
 
115
120
  **A day that recurs every year, with no founding date of its own, writes year `0`** — quoted, since every canonical date stating a day must be:
116
121
 
@@ -118,6 +123,7 @@ A build computes the next occurrence against the world's declared present the wa
118
123
  data:
119
124
  events:
120
125
  - when: "0.286"
126
+ summary: The harvest rite is kept.
121
127
  ```
122
128
 
123
129
  `when: "0.286"` is the two-hundred-eighty-sixth day of the year, every year — a harvest rite nobody dates to a founding. `recurs` is refused beside it, since the entry is already annual; `until` is allowed, and bounds how long the rite was kept.
@@ -14,7 +14,7 @@ HeroicLands notes begin with YAML frontmatter. A file is recognized as a note wh
14
14
  shortcode: harbor
15
15
  name: { full: Harbor, aliases: [The Harbor] }
16
16
  type: lore
17
- subType: concept
17
+ subType: economy
18
18
  description: A sheltered trading port.
19
19
  tags: [draft]
20
20
  data: {}
@@ -58,7 +58,7 @@ Write `government: null` for **complete anarchy**. Omitting the key leaves gover
58
58
  | Any | Explicit `null` | None; complete anarchy |
59
59
  | Any | Affiliation Address | None; the reference must resolve |
60
60
 
61
- These rules apply to every place subtype, including settlements, sites, structures, features, regions and worlds. Empty strings, numbers, lists, maps, references to another note type and unresolved references are errors. They do not declare anarchy. `domains`, `parents`, containment and capitals do not supply a government. The generated `governed_by` and `governed_places` lists use only explicit government references. Legacy affiliation `data.domains` is accepted temporarily but ignored; record any distinct ownership or influence in prose. See [government migration](../guides/government-migration.md).
61
+ These rules apply to every place subtype, including settlements, sites, structures, features, regions and worlds. Empty strings, numbers, lists, maps, references to another note type and unresolved references are errors. They do not declare anarchy. `parents`, containment and capitals do not supply a government. The generated **Governed by** and **Governed places** sections use only explicit government references.
62
62
 
63
63
  ## Publication and summaries
64
64