@heroiclands/package-build 22.28.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 (156) hide show
  1. package/CHANGELOG.md +72 -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 +125 -142
  6. package/docs/authoring/assets.md +1 -1
  7. package/docs/authoring/dates-and-calendars.md +12 -6
  8. package/docs/authoring/first-note.md +1 -1
  9. package/docs/authoring/frontmatter.md +2 -2
  10. package/docs/authoring/links-and-markup.md +145 -29
  11. package/docs/commands.md +8 -10
  12. package/docs/configuration.md +13 -11
  13. package/docs/content-format.md +3 -3
  14. package/docs/guides/book.md +59 -4
  15. package/docs/guides/icons.md +4 -5
  16. package/docs/guides/packs.md +6 -0
  17. package/docs/guides/reference-pages.md +21 -1
  18. package/docs/guides/release-and-deploy.md +17 -1
  19. package/docs/guides/site.md +17 -18
  20. package/docs/reference/format-details.md +904 -275
  21. package/docs/reference/note-types.md +282 -91
  22. package/docs/reference/theme-pages.md +58 -66
  23. package/engine/address-values.mjs +124 -4
  24. package/engine/address.mjs +44 -3
  25. package/engine/anchors.mjs +103 -3
  26. package/engine/art-slots.mjs +2 -9
  27. package/engine/base-compiler.mjs +25 -6
  28. package/engine/calendar-artifacts.mjs +4 -1
  29. package/engine/calendar-notes.mjs +166 -102
  30. package/engine/content-format-check.mjs +2 -3
  31. package/engine/content-format.mjs +44 -1
  32. package/engine/content-format.yaml +84 -16
  33. package/engine/content-images.mjs +10 -1
  34. package/engine/content-index.mjs +37 -9
  35. package/engine/content-links.mjs +24 -5
  36. package/engine/content-tables.mjs +24 -3
  37. package/engine/data-keys.mjs +347 -0
  38. package/engine/derived-sections.mjs +322 -0
  39. package/engine/diagnostics.mjs +28 -0
  40. package/engine/event-fields.mjs +187 -0
  41. package/engine/event-rows.mjs +126 -0
  42. package/engine/event-views.mjs +305 -0
  43. package/engine/exported-scene.mjs +29 -53
  44. package/engine/frontmatter-lint.mjs +103 -77
  45. package/engine/frontmatter.mjs +7 -2
  46. package/engine/generate.mjs +53 -0
  47. package/engine/generated-sections.mjs +223 -0
  48. package/engine/heading-attributes.mjs +4 -2
  49. package/engine/helpers.mjs +12 -1
  50. package/engine/holdings.mjs +12 -33
  51. package/engine/ids.mjs +17 -11
  52. package/engine/index.mjs +4 -4
  53. package/engine/infobox-render.mjs +21 -6
  54. package/engine/infobox.mjs +217 -99
  55. package/engine/journals.mjs +104 -47
  56. package/engine/literature-notes.mjs +136 -0
  57. package/engine/literature-works.mjs +161 -0
  58. package/engine/map-graphviz.mjs +4 -18
  59. package/engine/markdown-expressions.mjs +116 -11
  60. package/engine/metadata-index.mjs +34 -0
  61. package/engine/near-miss.mjs +90 -0
  62. package/engine/note-addresses.mjs +75 -19
  63. package/engine/note-dates.mjs +5 -3
  64. package/engine/note-event-terms.mjs +364 -0
  65. package/engine/note-events.mjs +823 -0
  66. package/engine/note-vocabulary.mjs +195 -92
  67. package/engine/office-holders.mjs +20 -54
  68. package/engine/packagebuild-index.mjs +16 -1
  69. package/engine/pdf-build.mjs +97 -60
  70. package/engine/pdf-index.mjs +263 -0
  71. package/engine/pdf-render.mjs +47 -5
  72. package/engine/place-relation-terms.mjs +174 -0
  73. package/engine/place-relations.mjs +72 -160
  74. package/engine/rank-ladder.mjs +14 -41
  75. package/engine/reckoning-markers.mjs +2 -0
  76. package/engine/region-events.mjs +6 -12
  77. package/engine/scenes.mjs +73 -468
  78. package/engine/site-build.mjs +74 -85
  79. package/engine/site-index.mjs +3 -1
  80. package/engine/site-maps.mjs +43 -29
  81. package/engine/site-preview.mjs +40 -31
  82. package/engine/social-ties.mjs +2 -1
  83. package/engine/sql-tables.mjs +212 -9
  84. package/engine/standing-terms.mjs +145 -6
  85. package/engine/standings.mjs +37 -49
  86. package/engine/stub-lint.mjs +6 -0
  87. package/engine/web-wikilinks.mjs +21 -1
  88. package/engine/wikilink-syntax.mjs +34 -4
  89. package/engine/wikilinks.mjs +27 -2
  90. package/hugo-theme/layouts/partials/infobox/entry.html +4 -1
  91. package/hugo-theme/layouts/partials/page-body.html +0 -2
  92. package/hugo-theme/static/css/style.css +25 -55
  93. package/package.json +1 -2
  94. package/packagebuild-metadata.jsonl +13 -13
  95. package/sohl/default-item-art.mjs +6 -6
  96. package/sohl/note-schemas.mjs +8 -73
  97. package/types/engine/address-values.d.mts +50 -3
  98. package/types/engine/address.d.mts +21 -0
  99. package/types/engine/anchors.d.mts +49 -2
  100. package/types/engine/art-slots.d.mts +1 -1
  101. package/types/engine/base-compiler.d.mts +13 -4
  102. package/types/engine/calendar-notes.d.mts +7 -0
  103. package/types/engine/content-format.d.mts +52 -0
  104. package/types/engine/content-images.d.mts +5 -1
  105. package/types/engine/content-tables.d.mts +9 -1
  106. package/types/engine/data-keys.d.mts +145 -0
  107. package/types/engine/derived-sections.d.mts +73 -0
  108. package/types/engine/diagnostics.d.mts +15 -0
  109. package/types/engine/event-fields.d.mts +99 -0
  110. package/types/engine/event-rows.d.mts +12 -0
  111. package/types/engine/event-views.d.mts +67 -0
  112. package/types/engine/exported-scene.d.mts +5 -2
  113. package/types/engine/frontmatter-lint.d.mts +3 -3
  114. package/types/engine/generated-sections.d.mts +143 -0
  115. package/types/engine/holdings.d.mts +6 -20
  116. package/types/engine/ids.d.mts +15 -12
  117. package/types/engine/index.d.mts +1 -1
  118. package/types/engine/infobox.d.mts +13 -3
  119. package/types/engine/journals.d.mts +24 -11
  120. package/types/engine/literature-notes.d.mts +29 -0
  121. package/types/engine/literature-works.d.mts +67 -0
  122. package/types/engine/map-graphviz.d.mts +2 -10
  123. package/types/engine/markdown-expressions.d.mts +12 -3
  124. package/types/engine/near-miss.d.mts +42 -0
  125. package/types/engine/note-addresses.d.mts +7 -1
  126. package/types/engine/note-event-terms.d.mts +68 -0
  127. package/types/engine/note-events.d.mts +71 -0
  128. package/types/engine/note-vocabulary.d.mts +37 -8
  129. package/types/engine/office-holders.d.mts +3 -0
  130. package/types/engine/pdf-index.d.mts +35 -0
  131. package/types/engine/pdf-render.d.mts +8 -2
  132. package/types/engine/place-relation-terms.d.mts +83 -0
  133. package/types/engine/place-relations.d.mts +11 -66
  134. package/types/engine/rank-ladder.d.mts +2 -0
  135. package/types/engine/region-events.d.mts +6 -12
  136. package/types/engine/scenes.d.mts +6 -32
  137. package/types/engine/site-build.d.mts +8 -22
  138. package/types/engine/site-maps.d.mts +15 -7
  139. package/types/engine/sql-tables.d.mts +77 -2
  140. package/types/engine/standing-terms.d.mts +37 -4
  141. package/types/engine/standings.d.mts +14 -9
  142. package/types/engine/wikilink-syntax.d.mts +20 -0
  143. package/types/engine/wikilinks.d.mts +3 -2
  144. package/docs/guides/government-migration.md +0 -52
  145. package/engine/itinerary-scenes.mjs +0 -166
  146. package/engine/lore-events.mjs +0 -197
  147. package/engine/map-notes.mjs +0 -1309
  148. package/engine/map-raster.mjs +0 -51
  149. package/hugo-theme/layouts/partials/holdings/entry.html +0 -21
  150. package/hugo-theme/layouts/partials/holdings/kind-groups.html +0 -71
  151. package/hugo-theme/layouts/partials/holdings.html +0 -61
  152. package/hugo-theme/layouts/partials/place-map.html +0 -9
  153. package/types/engine/itinerary-scenes.d.mts +0 -29
  154. package/types/engine/lore-events.d.mts +0 -14
  155. package/types/engine/map-notes.d.mts +0 -297
  156. package/types/engine/map-raster.d.mts +0 -8
@@ -120,20 +120,45 @@ in a compendium journal with no further edit. A `Name` row stands first on
120
120
  every note, because every note has one. An `Aliases` row follows it when the
121
121
  note names any aliases, preserving their authored order.
122
122
 
123
- A few keys carry no row, and the reason in each case is one of exactly two —
123
+ A few keys carry no row, and the reason in each case is one of exactly three —
124
124
  the key is **machinery**, steering a build or an interface rather than
125
- describing the subject, or it is an **image**, which rule 2 keeps out of the
126
- box:
127
-
128
- | key | why it carries no row |
129
- | ------------------------ | ------------------------------------------------ |
130
- | `templatePriority` | template machinery, not a fact about the subject |
131
- | `color` | sidebar machinery, not a fact about the subject |
132
- | the art slots, `overlay` | an image, which rule 2 keeps out of the box |
133
-
134
- A field whose value is a **mapping** carries no row either — a governance
135
- ladder or a wall layout has no summary shape — and neither does one the note
136
- left empty.
125
+ describing the subject; it is an **image**, which rule 2 keeps out of the box;
126
+ or it is a **source system's own detail**, which no surface's box shows:
127
+
128
+ | key | why it carries no row |
129
+ | ---------------------------------------------------------------------------- | ---------------------------------------------------------- |
130
+ | `templatePriority` | template machinery, not a fact about the subject |
131
+ | `color` | sidebar machinery, not a fact about the subject |
132
+ | `id` | document identity machinery, not a fact about the subject |
133
+ | `pack`, `packFolder` | compendium routing machinery, not a fact about the subject |
134
+ | `events` | chronology machinery, not a summary row |
135
+ | a calendar's `months`, `weekdays`, `seasons`, `namedDays`, `eras`, `formats` | calendar machinery, not a summary row |
136
+ | a map's `scene`, `fixup` | canvas machinery, not a summary row |
137
+ | `harnworld` | HârnWorld source detail, which no surface's box shows |
138
+ | the art slots | an image, which rule 2 keeps out of the box |
139
+
140
+ **A field whose value holds maps is drawn by what its declaration says the
141
+ maps are**, and a map is never set as text:
142
+
143
+ - **A map with declared keys** takes one row per key that holds a value, in
144
+ declared order, labelled by the key and carrying its value. A list of words under a key is one row of
145
+ them, comma-joined. A key holding nothing — `null`, `""`, `[]` — takes no
146
+ row, and a map with nothing to show takes none at all.
147
+ - **A map keyed by Address** relates the note to others: `socialTies` and an
148
+ affiliation's `relations` take one row per term — `Patron`, `Rival`,
149
+ `Aligned` — whose value is the targets, each linked.
150
+ - **A map keyed by Shortcode** weighs each thing it names: a mystery's
151
+ `skillAptitudes` is one row, each skill linked with its weight beside it —
152
+ `Sword (+5)`, `Combat skills (-2)`.
153
+ - **A list of maps** keeps the rendering its field was built for — a place's
154
+ `borders` and `routes` as linked places with their bearings, an affiliation's
155
+ `governance.ranks` and `governance.offices` as one row per rung or post — or
156
+ is withheld above as machinery.
157
+
158
+ **A being's memberships are a section of their own**, titled
159
+ **Affiliations**, after the profile rows: one line per membership, in the
160
+ order the note writes them — `War Chief, Hárár (5), of Vrystwald Tribes`. See
161
+ [the bodies a being belongs to](#the-bodies-a-being-belongs-to-and-its-standing-in-each).
137
162
 
138
163
  A being's `age`, `height`, `weight` and `appearance.*` compose into a single
139
164
  **Appearance** clause rather than taking six rows of their own: _Age 34, 6′ 1″,
@@ -230,12 +255,12 @@ A section says how it is arranged, and a renderer switches on that and on a
230
255
  value's `kind` — never on a field name, which is what keeps a field list from
231
256
  leaking back into a template.
232
257
 
233
- | `layout` value | shape | what carries it | where it is used |
234
- | -------------- | ------------------------------- | --------------- | -------------------------- |
235
- | `rows` | label/value pairs, one per line | `rows` | a profile |
236
- | `grid` | short label/value cells | `cells` | attributes, armour aspects |
237
- | `runin` | groups of comma-joined entries | `groups` | skills, equipment |
238
- | `list` | one entry per line | `entries` | mystical abilities |
258
+ | `layout` value | shape | what carries it | where it is used |
259
+ | -------------- | ------------------------------- | --------------- | ----------------------------------------- |
260
+ | `rows` | label/value pairs, one per line | `rows` | a profile |
261
+ | `grid` | short label/value cells | `cells` | attributes, armour aspects |
262
+ | `runin` | groups of comma-joined entries | `groups` | skills, equipment |
263
+ | `list` | one entry per line | `entries` | mystical abilities, a being's memberships |
239
264
 
240
265
  | `kind` value | the value is |
241
266
  | ------------ | ------------------------------- |
@@ -248,6 +273,9 @@ leaking back into a template.
248
273
  A website renders a link by its `url`, a compendium journal by its `uuid`, and
249
274
  the book by the `address`, which is the entry's own label in the volume. A
250
275
  reference the index could not reach keeps its words rather than being dropped.
276
+ An entry of a `runin` group or a `list` section is a link, and may carry a
277
+ `lead`: plain text set before it, so a membership line — `Captain, Blade (4), of
278
+ The Silent Talon Company` — links the body's name and nothing else.
251
279
 
252
280
  **Emitted shape**, as a page's front matter carries it:
253
281
 
@@ -263,11 +291,18 @@ infoboxes:
263
291
  - label: Name
264
292
  kind: text
265
293
  value: Brànwâal Dôrgaar
266
- - label: Affiliations
294
+ - label: Homes
267
295
  kind: links
268
296
  value:
269
- - text: The Silent Talon Company
270
- url: /thalorna/affiliation-slntlncmpny/
297
+ - text: Vylar
298
+ url: /thalorna/place-vylar/
299
+ - id: affiliations
300
+ label: Affiliations
301
+ layout: list
302
+ entries:
303
+ - lead: "Captain, Blade (4), of "
304
+ text: The Silent Talon Company
305
+ url: /thalorna/affiliation-slntlncmpny/
271
306
  - id: sohl
272
307
  kind: system
273
308
  system: sohl
@@ -350,6 +385,27 @@ flow collection is formatted into one of those forms; folded collections are
350
385
  not used. `package-build format --write` applies this rule and the top-level
351
386
  order without changing the Markdown body.
352
387
 
388
+ #### What checks a system block
389
+
390
+ A system block — `sohl:` or `hm3:` — is checked against that system's own
391
+ field schema: the fields the system declares for each document type, with
392
+ their shapes. None of the `data:` vocabulary applies inside it, the inner-key
393
+ rule included, and a key the system's schema does not declare is an error at
394
+ its own line.
395
+
396
+ A block is checked only where both of these hold:
397
+
398
+ - **The package declares the system** — under `systems:`, as a pack's
399
+ `system:`, or as the system the package is or requires. A block for a system
400
+ the package does not declare is not checked.
401
+ - **The system's fields are known.** The `sohl:` block is held to the note
402
+ schemas the build carries; any other system's block is held to the
403
+ `itemBuilders` registry that declares it. Where a declared system has
404
+ neither, the lint says that system's block is unchecked, and a key inside it
405
+ is discarded at compile.
406
+
407
+ A `dnd5e:` block has no field schema, so nothing checks it.
408
+
353
409
  #### Dates and calendars
354
410
 
355
411
  A canonical date is `<year>[.<day>[:HHMMSS]]`. The day is one-based within the world's year, bound against `data.year.days` on the world's `place` note. A tree whose notes declare no world year bounds no day: the value is read as written, however large. `720` covers the whole year; `720.136` covers that day; `720.136:143005` identifies one second. Negative years are valid. Prefix either form with `~` to express uncertainty beyond its written interval. `unknown` is allowed only in fields that accept an unknown occurrence.
@@ -408,11 +464,28 @@ subject — a weapon's weight, an affliction's transmission, a being's species
408
464
  and every note type declares which keys it may carry. A misspelled key is a
409
465
  finding in either region.
410
466
 
467
+ **So is every map inside it, at every depth.** A field whose value holds maps
468
+ — a map such as `harnworld`, a list of maps such as `borders` or `months`, a map
469
+ keyed by Address whose values are maps such as `affiliations` — declares the
470
+ keys those maps take, which of them are required, and what each holds. A key a
471
+ field does not declare is an error at that key's own line and column, however
472
+ deeply it is nested: `data.governance.offices.Chancellor.holders[0].stat` is
473
+ refused at `stat`, with the declared key it was probably meant to be. A
474
+ required key left out is an error at the map that should carry it, and a value
475
+ of the wrong kind is an error at the value. A dotted property such as
476
+ `appearance.eye_color` closes its container the same way, so `appearance`
477
+ takes only the keys the type's table lists. The
478
+ [note-type reference](note-types.md) tabulates every inner key, generated from
479
+ the same declarations the lint reads; an event's keys are tabulated under
480
+ [Events](#events). Two things are outside this rule. A system block follows its
481
+ own schema — see [What checks a system block](#what-checks-a-system-block). A
482
+ map note's `data.scene` is an exported Foundry Scene and keeps Foundry's own
483
+ keys; its table row says so, beginning **Keys not declared here:**.
484
+
411
485
  Every note type may put a pinned document id in `data.id`, a shared compendium
412
- route in `data.pack`, a shared folder Address in `data.packFolder`, and source
413
- details in `data.harnworld`. A system block's `pack` or `packFolder` overrides
414
- the shared value for that system. A `being` may also describe its social profile
415
- in `data.social`.
486
+ route in `data.pack`, a shared folder Address in `data.packFolder`, and its
487
+ HârnWorld source details in `data.harnworld`. A system block's `pack` or
488
+ `packFolder` overrides the shared value for that system.
416
489
 
417
490
  **Tags are open, except the ones that classify.** A tag naming a theme or a region — `underworld`,
418
491
  `byzaria`, `riverlands` — is the author's own and this build has no opinion about it.
@@ -693,10 +766,10 @@ the art it writes (`emitsArt`). A second table of iconless types would be a tabl
693
766
  free to drift from what is actually emitted, which is the defect rather than the
694
767
  check.
695
768
 
696
- #### The four art slots
769
+ #### The art slots
697
770
 
698
771
  A note declares the art its document needs, and every other image in it is
699
- inline. All four slots are ordinary `Address` fields declaring a default type,
772
+ inline. Every slot is an ordinary `Address` field declaring a default type,
700
773
  exactly as `seat` declares `place` — a bare shortcode takes its type from the
701
774
  declaration, and qualification climbs the same short-form ladder every other
702
775
  link uses.
@@ -705,10 +778,9 @@ link uses.
705
778
  | ----------- | ------------ | --------------- | ----------------------------- | ----------------------------------------- |
706
779
  | `icon` | `icon` | `icon`, `image` | `document.img` | every Actor/Item type, and embedded items |
707
780
  | `tokenIcon` | `icon` | `icon`, `image` | `prototypeToken.texture.src` | Actor types |
708
- | `bgImage` | `image` | `icon`, `image` | `background.src` | map types |
709
781
  | `banner` | `image` | `icon`, `image` | the site hero image, 1792×768 | any note; not a Foundry field |
710
782
 
711
- All four are authored under `data:`:
783
+ Every slot is authored under `data:`:
712
784
 
713
785
  ```yaml
714
786
  data:
@@ -718,8 +790,8 @@ data:
718
790
 
719
791
  **Every slot accepts a second type beyond the one it defaults to**, and the two
720
792
  defaults pair with the same accepted set: `icon` and `tokenIcon` default to
721
- `icon`, `bgImage` and `banner` default to `image`, and all four accept `icon`
722
- **and** `image` regardless of which one they default to. A bare shortcode still
793
+ `icon`, `banner` defaults to `image`, and every slot accepts `icon` **and**
794
+ `image` regardless of which one it defaults to. A bare shortcode still
723
795
  takes the slot's default — `icon: anvil` above names an `icon`, not an `image`
724
796
  — and it is a **qualified** value, one that states its own type, that the
725
797
  accepted set governs. `sohl-kethira-basic` writes an `icon` slot this way
@@ -733,7 +805,7 @@ data:
733
805
 
734
806
  That value is accepted because `image` is in the slot's accepted set, not
735
807
  because it matches the default — `icon` still defaults to `icon`. `audio` is
736
- refused at all four slots: a sound is not art, and a value naming one — `icon:
808
+ refused at every slot: a sound is not art, and a value naming one — `icon:
737
809
  audio-thunder`, say — is an error naming the set the slot accepts, never a
738
810
  silent fall back to the note's default art.
739
811
 
@@ -743,22 +815,35 @@ are, so a key legal everywhere is stated once here rather than repeated in
743
815
  twenty-five tables where the one that was mistyped would be the one nobody
744
816
  noticed:
745
817
 
746
- | shared `data` property | Values | Description |
747
- | ---------------------- | ---------------------- | -------------------------------------------------------------------- |
748
- | `id` | `string` | A pinned document identity. |
749
- | `pack` | `string` | The shared compendium route. |
750
- | `packFolder` | `Address` or pack map | The shared compendium folder Address. |
751
- | `harnworld` | `Map<string, unknown>` | HârnWorld source details. |
752
- | `icon` | `Address` | The document's profile art — an `icon` address, resolved into `img`. |
753
- | `banner` | `Address` | The page's hero image — an `image` address, cut to 1792×768. |
818
+ | shared `data` property | Values | Description |
819
+ | ---------------------- | --------------------- | -------------------------------------------------------------------- |
820
+ | `id` | `string` | A pinned document identity. |
821
+ | `pack` | `string` | The shared compendium route. |
822
+ | `packFolder` | `Address` or pack map | The shared compendium folder Address. |
823
+ | `harnworld` | `{ realm?, ritual? }` | HârnWorld source details. |
824
+ | `harnworld.realm` | `string` | The HârnWorld realm the subject belongs to. |
825
+ | `harnworld.ritual` | `string[]` | The HârnWorld religions the subject observes. |
826
+ | `icon` | `Address` | The document's profile art — an `icon` address, resolved into `img`. |
827
+ | `banner` | `Address` | The page's hero image — an `image` address, cut to 1792×768. |
828
+
829
+ `data.harnworld` takes two keys and nothing else: `realm`, a string naming the
830
+ HârnWorld realm the subject belongs to, and `ritual`, a list of strings naming
831
+ the religions it observes. Both are optional. The infobox does not show either.
832
+
833
+ ```yaml
834
+ data:
835
+ harnworld:
836
+ realm: Kaldor
837
+ ritual: [Larani, Peoni]
838
+ ```
754
839
 
755
840
  `icon` is legal everywhere because most types compile into a document that
756
841
  carries one; where a type's passes emit none, the lint says so and the value is
757
842
  left alone, because a page template may still read it. `banner` reaches no
758
843
  compiled document at all, and a page is what every note publishes.
759
844
 
760
- The other two are narrower, and each type's own table names them: `tokenIcon`
761
- on the Actor types, `bgImage` on a map.
845
+ `tokenIcon` is narrower, and the Actor types' own tables name it. A map takes
846
+ no art slot: its Scene is exported from Foundry and names its own art.
762
847
 
763
848
  **A portrait is not one of them.** A picture of the subject is a picture, so it
764
849
  is authored in the prose that describes the subject, as an ordinary embedded
@@ -837,7 +922,7 @@ and the whole of it is the suffix.
837
922
 
838
923
  ```markdown
839
924
  ![A map of the Vale](images/maps/valeofthorns.webp) <!-- this package's -->
840
- ![A shield](sohl/assets/icons/noun/shield.svg) <!-- the sohl package's -->
925
+ ![A shield](sohl/assets/icons/noun/shieldnn.svg) <!-- the sohl package's -->
841
926
  ```
842
927
 
843
928
  The four forms, for a `harnensemble` note (the `harnensemble` content package
@@ -850,14 +935,14 @@ ships as the Foundry module `harn-ensemble`) writing `images/map.webp`:
850
935
  | **Web** | `https://cdn.heroiclands.org/harnensemble/images/map.webp` |
851
936
  | **Book** | `assets/images/map.webp`, staged beside the Typst source |
852
937
 
853
- And for the same note writing `sohl/assets/icons/noun/shield.svg`, a file the
938
+ And for the same note writing `sohl/assets/icons/noun/shieldnn.svg`, a file the
854
939
  system ships and this repository does not hold:
855
940
 
856
941
  | Surface | Address |
857
942
  | ----------- | ------------------------------------------------------------- |
858
- | **Foundry** | `systems/sohl/assets/icons/noun/shield.svg` |
859
- | **Local** | `assets/icons/noun/shield.svg`, in the `sohl` repository |
860
- | **Web** | `https://cdn.heroiclands.org/sohl/icons/noun/shield.svg` |
943
+ | **Foundry** | `systems/sohl/assets/icons/noun/shieldnn.svg` |
944
+ | **Local** | `assets/icons/noun/shieldnn.svg`, in the `sohl` repository |
945
+ | **Web** | `https://cdn.heroiclands.org/sohl/icons/noun/shieldnn.svg` |
861
946
  | **Book** | not carried, unless a declared replacement carries it instead |
862
947
 
863
948
  **The content package name and Foundry id are separate values.**
@@ -937,8 +1022,8 @@ whole `assets/` tree and the directory names inside it are its own business:
937
1022
  is that package's by the same rule that claims `icons/…` and `images/…`.
938
1023
 
939
1024
  **Where a pathname is still authored, it follows this rule.** That is the
940
- address of an image in a note's body, and a map note's `overlay`. The art
941
- fields do not: `icon`, `tokenIcon`, `bgImage` and `banner` name
1025
+ address of an image in a note's body. The art fields do not: `icon`,
1026
+ `tokenIcon` and `banner` name
942
1027
  addresses, and the path comes from the record the resolved address points at —
943
1028
  which already carries the owning package, so there is nothing for a first
944
1029
  segment to state.
@@ -958,9 +1043,8 @@ exists.
958
1043
 
959
1044
  No other art slot states a size, and none of them asks anything of a picture's
960
1045
  dimensions. An `icon` is drawn at a nominal size per medium whatever its file
961
- holds; a map's `bgImage` sets its own scene's dimensions, so it is whatever size
962
- the map is; and a picture written in prose is fitted to the room it has. Those
963
- three accept whatever they are given.
1046
+ holds, and a picture written in prose is fitted to the room it has. Both accept
1047
+ whatever they are given.
964
1048
 
965
1049
  It is an `Address` all the same, defaulting to type `image`, so a section note
966
1050
  writes `banner: skillbnr` and a note borrowing another package's plate writes
@@ -1514,8 +1598,9 @@ information, because the field already said what kind of thing it points at.
1514
1598
 
1515
1599
  The frontmatter lint checks scalar Addresses, entries in Address lists, and
1516
1600
  Address map keys at the entry's own location. Segments contain lowercase ASCII
1517
- letters and digits; wikilink brackets, labels, anchors, and spaces do not belong
1518
- in these fields. Optional null values and empty lists or maps express no
1601
+ letters and digits; wikilink brackets, labels and spaces do not belong in these
1602
+ fields, and an anchor belongs only in a field that accepts one — see _Anchors_
1603
+ below. Optional null values and empty lists or maps express no
1519
1604
  reference. Grammar and accepted types are checked independently of whether a
1520
1605
  target exists.
1521
1606
 
@@ -1555,7 +1640,7 @@ a candidate to weigh — it takes the default outright, every time — and the
1555
1640
  accepted set is what a value that states its own type is checked against
1556
1641
  instead: naming any member of the set is as valid as naming the default
1557
1642
  itself, and naming a type outside it is an error against the set, never
1558
- against the default alone. [The four art slots](#the-four-art-slots) are
1643
+ against the default alone. [The art slots](#the-art-slots) are
1559
1644
  declared exactly this way — each one accepts a second type beyond the one a
1560
1645
  bare shortcode takes.
1561
1646
 
@@ -1579,6 +1664,52 @@ Brackets belong in prose, where a link sits inside a sentence and needs marking
1579
1664
  off from the words around it. A frontmatter value has nothing to be marked off
1580
1665
  from.
1581
1666
 
1667
+ #### Anchors
1668
+
1669
+ An Address may end in `#<anchor>`, naming a place inside the note it addresses —
1670
+ a section of its prose, or one of its events. Every written form takes one:
1671
+
1672
+ ```text
1673
+ thalorna-note-place-ironfells#sack the full Address, anchored
1674
+ place-ironfells#sack type and shortcode, anchored
1675
+ ironfells#sack a bare shortcode, where the field supplies the type
1676
+ ```
1677
+
1678
+ The anchor is read the same way in a frontmatter field and in a wikilink: it is
1679
+ everything after the first `#`, and what precedes it is an ordinary Address.
1680
+
1681
+ **Every anchor has one of two kinds**, from what declares it:
1682
+
1683
+ | anchor kind | declared by |
1684
+ | ----------- | ----------------------------------------------------------------------------------------------- |
1685
+ | `prose` | any `{#slug}` in the note's body — on a heading, a caption, a block, an alert, a poem or a span |
1686
+ | `event` | the `id` of an entry in `data.events` — see [Events](#events) |
1687
+
1688
+ **A note's anchors are one namespace.** An event's `id` that equals any other
1689
+ anchor slug in the same note is an error at the `id`, as two equal headings
1690
+ already are.
1691
+
1692
+ **A frontmatter field accepts an anchor only where it declares the kinds it
1693
+ takes.** Every other Address field refuses `#<anchor>` with an error at that
1694
+ value. A field keyed by Address takes none, so an Address map key is always a
1695
+ plain Address. The fields that take one:
1696
+
1697
+ | field | anchor kinds | without an anchor |
1698
+ | ------------------------------------- | ------------ | ------------------------------------------------------ |
1699
+ | `events[].follows[].event` | `event` | names a note holding exactly one event |
1700
+ | `events[].where.reach[].attributedTo` | `event` | names a lore note, or a note holding exactly one event |
1701
+ | `made`, `lost` (every gear type) | `event` | names a note holding exactly one event |
1702
+ | `subjects` (a `literature` note) | `event` | names a note of any type, as every subject does |
1703
+
1704
+ An anchored Address resolves when its note resolves, declares that anchor, and
1705
+ the anchor's kind is one the field takes. Each failure has its own message: the
1706
+ note does not resolve; the note declares no such anchor; or the anchor is a
1707
+ `prose` anchor, not an `event` one.
1708
+
1709
+ **A wikilink names a `prose` anchor only.** `[[lore-crown#founding|the founding]]`
1710
+ where `founding` is an event's `id` is an error at the link, on every surface:
1711
+ prose links to the note, not to an event. Write `[[lore-crown|the founding]]`.
1712
+
1582
1713
  ### Wikilinks
1583
1714
 
1584
1715
  A **`Wikilink`** is how body prose names something:
@@ -1900,7 +2031,7 @@ replacement is consulted **before** the local address; a foreign lookup only
1900
2031
 
1901
2032
  **An asset type exists so a note can name a file and a package can substitute
1902
2033
  it.** Nothing about a font answers to either half. No note names a typeface —
1903
- the art slots are `icon`, `tokenIcon`, `bgImage` and `banner` — and substituting
2034
+ the art slots are `icon`, `tokenIcon` and `banner` — and substituting
1904
2035
  one package's font for another's is not something anyone wants.
1905
2036
 
1906
2037
  **Neither consumer of a font can use an address.** A stylesheet names a file
@@ -2010,7 +2141,9 @@ Every typed note requires a nonempty body after its closing frontmatter fence.
2010
2141
  An empty or whitespace-only body is an error, regardless of description or
2011
2142
  `tags: [draft]`. This includes `folder` and `homepage` notes. Untyped vault
2012
2143
  scaffolding is excluded. A nonempty body with fewer than 25 prose words warns
2013
- unless tagged `draft`; the tag never exempts an empty body.
2144
+ unless tagged `draft`; the tag never exempts an empty body. A `folder` note is
2145
+ held only to the nonempty rule: any body, a placeholder or a single line
2146
+ included, passes with or without `draft`.
2014
2147
 
2015
2148
  The `lint`, `content-index`, `package compile`, `site` and `pdf` commands enforce
2016
2149
  body errors. Write a short beginning and tag it `draft` when work is unfinished.
@@ -2055,7 +2188,7 @@ same.
2055
2188
  | A lone heading | no | The same |
2056
2189
  | `_To be written._` | no | The same |
2057
2190
 
2058
- An HTML comment is deliberately not empty, but an invisible marker does not supply prose. Replace placeholder-only content with written text.
2191
+ An HTML comment is deliberately not empty, but an invisible marker does not supply prose. Replace placeholder-only content with written text. A `folder` note is the exception: any of these bodies satisfies it, and the lint reports nothing.
2059
2192
 
2060
2193
  #### What a stub emits
2061
2194
 
@@ -2116,7 +2249,7 @@ so adding a type means answering the question rather than inheriting a default.
2116
2249
  relations rather than page links**: a border with a stub on the far side is a
2117
2250
  valid statement about the world and resolves. So does `parents` for the
2118
2251
  containment tree and `government` for governance — a stub appears in its region's
2119
- `contains` and its governing body's `governed_places`, rendered as plain text. What a stub
2252
+ **Within** and its governing body's **Governed places**, as plain text. What a stub
2120
2253
  cannot be is the target of a wikilink, because a wikilink points at a page.
2121
2254
 
2122
2255
  ### What a note produces
@@ -2296,7 +2429,9 @@ The contraband is behind the false wall.
2296
2429
  ```
2297
2430
 
2298
2431
  The section runs from the heading to the next heading that opens a page, which
2299
- is the span Foundry makes one page of.
2432
+ is the span Foundry makes one page of. A captioned item inside the section is
2433
+ withheld with it in Foundry: its own page and the page that resumes the section
2434
+ after it are visible to the GM alone.
2300
2435
 
2301
2436
  | Surface | What a reader meets |
2302
2437
  | ------- | ----------------------------------------------------------------------------------------------------------------- |
@@ -2451,6 +2586,12 @@ resolves it to what that surface serves:
2451
2586
  A fenced `sql` block renders a table from the content index. A query that
2452
2587
  selects no rows is a build error unless its fence states `{allow-empty=true}`.
2453
2588
 
2589
+ **An Address is a string in every relation**: the full canonical Address, with
2590
+ `#<anchor>` where it carries one. A fence compares one as it is written —
2591
+ `list_contains(data.parents, 'thalorna-note-place-xerathia')`,
2592
+ `data.government = p.address.canonical` — in this package's `notes` and in each
2593
+ dependency's alike, although the published index writes each as an object.
2594
+
2454
2595
  SQL fences query the content index through DuckDB. The SQL dialect is DuckDB's.
2455
2596
 
2456
2597
  ````markdown
@@ -2507,6 +2648,41 @@ The ladder is what makes "how finished is this?" a query:
2507
2648
  SELECT state, count(*) AS n FROM entries GROUP BY state ORDER BY state
2508
2649
  ```
2509
2650
 
2651
+ **`events`** is one row per event — per entry of `data.events` on every
2652
+ `lore`, `place` and `affiliation` note, stubs included — so a chronology is a
2653
+ query rather than a list kept by hand:
2654
+
2655
+ ````markdown
2656
+ ```sql
2657
+ SELECT note AS _ref, "when" AS "When", summary AS "What happened"
2658
+ FROM events
2659
+ WHERE kind IN ('war', 'siege', 'battle')
2660
+ ORDER BY whenSort
2661
+ ```
2662
+ ````
2663
+
2664
+ | Column | What it holds |
2665
+ | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2666
+ | `note` | The canonical Address of the note the event is written on. |
2667
+ | `address` | The event's own Address: `note#id` where the event has an `id`, the note's Address alone where it has none. |
2668
+ | `id`, `kind`, `depth`, … | Every key of an event, each its own column under its own name — `id`, `kind`, `depth`, `when`, `until`, `recurs`, `summary`, `standing`, `names`, `where`, `who`, `follows`, `accounts`, `unresolved`, `sources`, `stated`. |
2669
+ | `whenSort`, `untilSort` | The date's position on the canonical axis: the canonical year, with a day as its fraction of the year where the calendar states the year's length. `ORDER BY whenSort` is date order. |
2670
+ | `whenYear`, `untilYear` | The canonical year alone, for a filter such as `whenYear BETWEEN 200 AND 299`. |
2671
+
2672
+ `when` and `until` read as the text the note wrote, `~` included. The sort
2673
+ keys and years are positions on the canonical axis, which counts a year `0`
2674
+ that written dates do not: a year written after zero keeps its number, and one
2675
+ written before zero sits one higher, so `when: -250` has a `whenYear` of
2676
+ `-249`. `_ref` takes a note's Address, never an anchored one, so a table links
2677
+ each row through `note` rather than `address`. A key no
2678
+ event writes is still a column, `NULL` in every row, and so is a sort key for
2679
+ a date with no position on the axis — `unknown`, or a year-`0` day that recurs
2680
+ every year. Every Address is a string, as in every other relation, and a list
2681
+ stays a list: `list_contains("where".locus, 'thalorna-note-place-ironfells')`.
2682
+ `when` and `where` are SQL keywords, so a query names those columns in double
2683
+ quotes, `"when"` and `"where"`. A note tagged `gm` contributes no row on a
2684
+ public surface.
2685
+
2510
2686
  **`market`** is the six-step market scale as a relation — `value`, `name`,
2511
2687
  `trade` — so a table prints `village` beside the number a note wrote without a
2512
2688
  second copy of the scale living in authored content.
@@ -2544,6 +2720,7 @@ ORDER BY name.full
2544
2720
  ```
2545
2721
  ````
2546
2722
 
2723
+ Its events are `sohl.events`, read exactly as this package's own `events`.
2547
2724
  This package's own notes stay at the unqualified `notes`, and a query may read
2548
2725
  both at once — joining your beings against the skills they cite is one `FROM`
2549
2726
  clause. It needs no fetch and no configuration: a dependency's published index
@@ -2665,9 +2842,9 @@ Each numbered type has its own counter. Websites and Foundry number within a not
2665
2842
 
2666
2843
  `{{ref "#trade"}}` displays the numbered label as a link. `form="full"` includes caption text and `form="title"` displays the caption alone. Use title form for an unnumbered caption. Cross-note references can name the note address before the anchor, such as `{{ref "place-harbor#trade"}}`; the displayed number belongs to the target on the surface rendering it. Links inside caption text contribute their visible text to references, so the reference does not contain a nested link.
2667
2844
 
2668
- Foundry gives a captioned item its own JournalEntryPage. A solitary image with a plain caption can use an image page; captions with inline markup and other items use text pages. On the website and in the book the item stays in the flow of the surrounding page.
2845
+ Foundry gives a captioned item a JournalEntryPage holding the item alone, named for its number or, unnumbered, for the caption's visible text — links and emphasis reduced to the words a reader sees. A solitary image with a plain caption can use an image page; captions with inline markup and other items use text pages. The body after the item resumes on a continuation page carrying the interrupted section's name, level and classes, with its title hidden; nothing is emitted when the next page begins straight after the item. On the website and in the book the item stays in the flow of the surrounding page.
2669
2846
 
2670
- **Migration:** `:::figure` is no longer supported. Move the former `///` caption before the item as `:@ Caption {#id}` and remove the figure wrapper. To caption a group or passage, put it inside a generic fenced div and caption that div with an explicit type if needed. `///` is no longer a caption delimiter.
2847
+ To caption a group or passage, put it inside a generic fenced div and caption that div, with an explicit type where the inferred one does not fit.
2671
2848
 
2672
2849
  ##### Fenced divs
2673
2850
 
@@ -2731,8 +2908,6 @@ Attributes follow the marker and apply to the alert:
2731
2908
 
2732
2909
  Use `#id`, `.class` and named attributes in the shared braced grammar. The marker determines the default label, icon and color. An authored `title` replaces the default **Note**, **Tip**, **Important** or **Warning** heading while preserving the alert type’s icon and color. Event-handler attributes, malformed attributes, unknown alert types and empty alert bodies are errors. Ordinary blockquotes and alert examples inside literal code remain unchanged. A leading caption can describe an alert as a quote block, normally with the `prose` type or an explicit `example` type.
2733
2910
 
2734
- Migrate former info blocks to `[!NOTE]` alerts and warn blocks to `[!WARNING]` alerts. The old named fences are errors. `:::secret` remains supported.
2735
-
2736
2911
  ##### Secret blocks
2737
2912
 
2738
2913
  `:::secret` sets GM material apart. Its optional attributes accept an identifier, classes and named attributes. `title` supplies its heading; without a title the heading is **Secret**:
@@ -2790,38 +2965,422 @@ All item types, including affiliation, affliction, armor, armorlocation, attribu
2790
2965
 
2791
2966
  An Item can mark its readable description with `# ... {#description}`. That heading starts a JournalEntryPage even when other pages precede it. Its Address is `<package>-note-<type>-<shortcode>#description`; the compiler resolves it to one `@UUID[...]` pointer. SoHL stores that pointer in `system.docHtml`, and HM3 stores the same pointer in `system.description` for Item subtypes that declare the field. An Item without this anchor points to its first page. Other pages remain addressable by their own anchors.
2792
2967
 
2968
+ ### Events
2969
+
2970
+ An **event** is one dated, attributed record of something that happened in the setting — a founding, a war, a fall, a plague, a birth. It is an entry in `data.events`, and three types carry that list: `lore`, `place` and `affiliation`. There is no event note type. A note holds the events that belong to it: a history note holds the event it describes, a place holds its raising and its ruin, an affiliation its founding and its dissolution. The schema is the same on all three types and on every subType.
2971
+
2972
+ Every key of an entry is closed, and so is every key of each map nested in one. A key this section does not list is an error at that key, and a value outside a key's closed list is an error at that value. Every Address an entry writes resolves in this package or a declared dependency, or it is an error at that Address.
2973
+
2974
+ An event appears on its note's page and in its Foundry journal as prose the note's body writes, and in the [event views](#event-views) the build appends to the notes it concerns. Nothing derived from it reaches a system field, an infobox row or a page's front matter, which carries `data.events` only as the note wrote it. The content index carries each entry's resolved dates under `resolvedDates.events`, and the [`events`](#content-tables) relation holds one row per entry.
2975
+
2976
+ #### The keys of an event
2977
+
2978
+ | event key | shape | required | what it records |
2979
+ | ------------ | ------------------------------------ | --------- | -------------------------------------------------------------------------- |
2980
+ | `id` | address segment | see below | The event's name within its note — lowercase letters and digits |
2981
+ | `kind` | one `eventKind` value | no | What sort of thing happened |
2982
+ | `depth` | one `depth` value | no | How far the event's history reaches |
2983
+ | `when` | a date, or `"0.<day>"` | yes | When it happened, or the anchor and first instance of an event that recurs |
2984
+ | `until` | a date | no | When a continuous event ended, or where a recurring series stopped |
2985
+ | `recurs` | `{ every }` or `{ on }` | no | How further occurrences are found; absent for an event that happened once |
2986
+ | `summary` | string | yes | What happened, stated plainly |
2987
+ | `standing` | one `standing` value | no | What the world's evidence supports |
2988
+ | `names` | `{ name, by, gloss? }[]` | no | The event's names in the world, each with who uses it |
2989
+ | `where` | `{ locus?, reach? }` | no | Where it happened, and where it was felt |
2990
+ | `who` | `{ ref, role }[]` | no | Who took part, and as what |
2991
+ | `follows` | `{ event, how, note? }[]` | no | The earlier events this one follows from |
2992
+ | `accounts` | `{ by, says, agrees, withholds? }[]` | no | What each people, polity, faith or place says about it |
2993
+ | `unresolved` | string list | no | What the world itself has not settled |
2994
+ | `sources` | Address list | no | The notes that state or support the event; each resolves |
2995
+ | `stated` | `{ calendar, text }` | no | The date as one tradition writes it in its own reckoning |
2996
+
2997
+ The nested entries, each closed the same way:
2998
+
2999
+ | nested key | shape | required | what it records |
3000
+ | ---------------------------- | ---------------------------------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------- |
3001
+ | `names[].name` | string | yes | One name the event goes by in the world |
3002
+ | `names[].by` | Address naming an `affiliation`, `lore`, `place`, `being` or `skill` note | yes | Who uses that name — a people, a polity, a faith, a place, a tongue; resolves |
3003
+ | `names[].gloss` | string | no | What the name means, or how it is used |
3004
+ | `where.locus` | list of Addresses, each defaulting to `place` | no | Where the event physically happened; each must resolve to a place |
3005
+ | `where.reach` | `{ place, how, knowledge, attributedTo? }[]` | no | Where the event was felt, and whether each place knows why |
3006
+ | `where.reach[].place` | an Address, defaulting to `place` | yes | A place where the event was felt; must resolve to a place |
3007
+ | `where.reach[].how` | string | yes | One clause: a consequence someone in that place could notice |
3008
+ | `where.reach[].knowledge` | one `knowledge` value | yes | Whether that place connects what it felt to this event |
3009
+ | `where.reach[].attributedTo` | Address, defaulting to `lore`, naming an event or a `lore` note | no | Only beside `knowledge: misattributed` — the cause that place names instead; resolves |
3010
+ | `who[].ref` | Address naming a `being`, `affiliation` or `lore` note | yes | A participant — a being, a people, an affiliation; resolves |
3011
+ | `who[].role` | one `role` value | yes | What the participant was to the event |
3012
+ | `follows[].event` | Address, defaulting to `lore`, anchored to an `event` where its note holds several | yes | The earlier event; resolves to exactly one event |
3013
+ | `follows[].how` | one `followsHow` value | yes | How this event follows from it |
3014
+ | `follows[].note` | string | no | One clause saying what connects the two |
3015
+ | `accounts[].by` | Address naming an `affiliation`, `lore`, `place` or `being` note | yes | Who holds the account; resolves |
3016
+ | `accounts[].says` | string | yes | What they say happened, in their terms |
3017
+ | `accounts[].agrees` | one `agrees` value | yes | How far their account agrees with `summary` |
3018
+ | `accounts[].withholds` | string | no | What they decline to say |
3019
+ | `stated.calendar` | Address, or a lore shortcode | yes | The calendar that tradition reckons in — a `lore` note with `subType: calendar`; resolves |
3020
+ | `stated.text` | string | yes | The date as that tradition writes it |
3021
+ | `recurs.every` | whole number of years, 1 or more | — | A period counted on the canonical axis from `when` |
3022
+ | `recurs.on` | list of dates, strictly increasing, each later than `when` | — | Recorded occurrences beyond the first, in place of a period |
3023
+
3024
+ `where.locus` and `where.reach[].place` default to `place`, so a bare shortcode there is read as one — `vale` is `place-vale` — and whatever the written form, the Address must resolve to a place note; one resolving to an affiliation, a lore note or anything else is an error at that key. `follows[].event`, `where.reach[].attributedTo` and `stated.calendar` default to `lore` in the same way, so `fallkhazturn` is `lore-fallkhazturn`. `who[].ref`, `accounts[].by` and `names[].by` state their type, and the type must be one their row names; a note of any other type is an error at that key naming the types it takes. `sources` takes a note of any type, written with its type: `lore-khazarfolk`, never `khazarfolk`. No Address is a bare name such as `The Vale`. `where.locus` in particular is never filled in from the note the event sits on — an event on a place is not assumed to have happened there, so a `locus` is written or absent.
3025
+
3026
+ #### Identity, and how an event is addressed
3027
+
3028
+ An event's `id` is an [anchor](#anchors) of kind `event`, in the one namespace the note's headings and blocks share. An event is addressed as its note's address when the note holds one event, and as `<note address>#<id>` when it holds several: `lore-thebargain`, `place-ironfells#sack`, `affiliation-crown#founding`.
3029
+
3030
+ - `id` is an address segment — lowercase ASCII letters and digits, nothing else.
3031
+ - `id` is unique within its note, and differs from every heading, caption and block anchor the note declares.
3032
+ - `id` is **required on every entry of a note holding two or more events**, and optional on a note holding one.
3033
+
3034
+ A note's prose prints one field of an event with an inline reference, `{{ref "place-ironfells#sack" field="when"}}`: the event's `when` or `until` as the note format prints a date, its `kind`, its `summary`, or the first of its `names`, as text and never a link, identically on every surface. The address names one event as a `follows[].event` does, or `"#<id>"` for one of the note's own. An address naming no event, a `prose` anchor, a `field` outside those five, or a field the event does not state is an error at the reference's position. The [authoring guide](../authoring/links-and-markup.md#an-events-date-inline) has examples.
3035
+
3036
+ A `follows[].event` resolves to exactly one event: a note holding one event, or `note#id`. Naming a note that holds several events without an `id` is an error, and so is naming an anchor the note does not declare or one that is not an event. An Address into another package is checked the same way against that package's published index, which carries each note's anchors with their kinds and each event's date.
3037
+
3038
+ #### Generated sections
3039
+
3040
+ The build appends sections to the end of a note's body, after everything the author wrote, each an H1 with a fixed anchor holding Markdown an author could have written. Every surface sets one as it sets an authored section: a page of the Foundry journal, a section of the website page listed in its table of contents, a section of the book.
3041
+
3042
+ | Section | Anchor | On | Content |
3043
+ | ----------------- | ---------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
3044
+ | Within | `within` | a `place` | the places whose `data.parents` names it, one paragraph to each kind of place, in the order the place vocabulary lists its `subType`s |
3045
+ | Governed by | `governedby` | a `place` | the affiliation its `data.government` names, as a list entry with the affiliation's kind |
3046
+ | Governed places | `governedplaces` | an `affiliation` | the places whose `data.government` names it, grouped as **Within** groups them |
3047
+ | Chronology | `chronology` | a `place` | an [event view](#event-views) |
3048
+ | Events | `events` | a `being`, an `affiliation`, a `lore` note of `culture` | an event view |
3049
+ | Accounts | `accounts` | an `affiliation`, a `place`, a `lore` note of `culture` | an event view |
3050
+ | What followed | `followed` | a note holding events | an event view |
3051
+ | In song and story | `insongandstory` | any note | the `literature` works whose `data.subjects` name the note or one of its events, as list entries with each work's `data.form` |
3052
+ | From here | `fromhere` | a `place` that states, or is named in, a border or route | the map drawn from the place, as an image |
3053
+
3054
+ - **Sections follow the author's text in the order of the table.**
3055
+ - **A section with nothing to show is not generated.**
3056
+ - **An author's own section replaces a generated one.** A note whose body declares a prose anchor with the section's slug — `# Within {#within}`, or a block or span with that `id` — gets no generated section for it, and its own section is left exactly as written. This is the one way to turn a section off, and the way to choose different contents for it.
3057
+ - **An entry is a link to the note it names**, written `[[<address>|]]` so each surface resolves it and shows the note's current name. An entry naming a stub, which publishes no page, is its name as plain text. The lists take in the places, affiliations and works a fetched index carries.
3058
+ - **The map is a drawing the build makes**, named `generated/from-<shortcode>.svg`. The website sets it inline so its place names are links, the Foundry compile stages it into the module at `assets/generated/`, and the book draws it beside its source. `generated/` is the build's: an authored image addressed there is an error. `site.maps: false` gives no place the section.
3059
+ - A stub publishes no page and is given no section.
3060
+
3061
+ #### Event views
3062
+
3063
+ The build appends sections to the end of a note's body that list the events concerning it — a region's chronology, the events a being took part in, the accounts a people gives, what followed an event. Each is an H1 with a fixed anchor holding a `sql` fence over the `events` relation, the same Markdown an author could write, so every surface sets it as it sets an authored section: a page of the Foundry journal, a section of the website page in its table of contents, a section of the book.
3064
+
3065
+ | View | Anchor | On | Rows | Columns |
3066
+ | ------------- | ------------ | ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- |
3067
+ | Chronology | `chronology` | a `place` | events whose `where.locus` names the place or a place below it in `parents`; events whose `where.reach` names one, with that entry's `how`; every `depth: world` event as context | What happened, When, Felt here |
3068
+ | Events | `events` | a `being`, an `affiliation`, a `lore` note of `subType: culture` | events whose `who[].ref` names the note, with the role it played | What happened, When, Role |
3069
+ | Accounts | `accounts` | an `affiliation`, a `place`, a `lore` note of `subType: culture` | each `accounts[]` entry the note gives, with the event it concerns | Event, When, What they say, Agrees |
3070
+ | What followed | `followed` | a note holding events | events whose `follows[].event` names one of this note's events, with how | What followed, When, How |
3071
+
3072
+ - **The views follow everything the author wrote**, in the order of the [generated sections](#generated-sections).
3073
+ - **A view with no rows is not generated.** A chronology is generated only where the place has rows of its own; the world events beside them are context and make no chronology by themselves.
3074
+ - **An author's own section replaces a view.** A note whose body declares a prose anchor with the view's slug — `# Chronology {#chronology}`, or a block or span with that `id` — gets no generated section for it, and its own section is left exactly as written. This is the one way to turn a view off, and the way to choose a different table: write the section and its own `sql` fence.
3075
+ - Places below a place are found by walking `parents` down from it, so an event felt in towns under two continents is in each continent's chronology and each region's.
3076
+ - A stub publishes no page and gets no view. The views read this package's own events; a dependency's are read with a fence over `<package>.events`.
3077
+
3078
+ #### What sort of event: `kind`
3079
+
3080
+ `kind` is closed. The groups are for reading; the list is one list.
3081
+
3082
+ | `eventKind` value | the event is |
3083
+ | ----------------- | ------------------------------------------------------------------------------------ |
3084
+ | `arrival` | A people or group comes to live in a land it did not hold |
3085
+ | `departure` | A people or group leaves a land it held |
3086
+ | `migration` | A people moves over a long span, through or across several lands |
3087
+ | `contact` | Two peoples meet for the first time, or after all memory of each other is lost |
3088
+ | `displacement` | A people is driven from its land by force or by catastrophe |
3089
+ | `founding` | A polity, order, settlement or other body comes into being |
3090
+ | `charter` | A body's rights, bounds or constitution are granted or written |
3091
+ | `accession` | A ruler or a ruling house takes power |
3092
+ | `secession` | A part breaks away from the body that held it |
3093
+ | `conquest` | One power takes and holds another's land or people by force |
3094
+ | `treaty` | Powers bind themselves by agreement — a peace, a league, a lease, a bargain |
3095
+ | `dissolution` | A body ceases to exist, by decision, absorption or decay |
3096
+ | `battle` | One engagement between armed forces |
3097
+ | `war` | A sustained armed conflict, spanning engagements |
3098
+ | `siege` | A fortified place is invested and held under attack |
3099
+ | `revolt` | Subjects rise against the power that rules them |
3100
+ | `fall` | A city, people or power is destroyed or overthrown |
3101
+ | `catastrophe` | A natural or magical disaster — a flood, an eruption, a working that escapes control |
3102
+ | `plague` | A sickness spreads through a population |
3103
+ | `famine` | Food fails across a land |
3104
+ | `raising` | A structure or settlement is built — a city, a wall, a temple, a road |
3105
+ | `ruin` | A structure or settlement falls into ruin or is razed |
3106
+ | `making` | An object, work or artefact is made |
3107
+ | `loss` | An object, work or body of knowledge is lost |
3108
+ | `discovery` | Something is found or first learned — a land, a route, a secret, a working |
3109
+ | `schism` | A faith, order or school divides |
3110
+ | `law` | A law, code or decree is made or abolished |
3111
+ | `council` | An assembly meets and decides |
3112
+ | `birth` | A person is born |
3113
+ | `death` | A person dies |
3114
+
3115
+ A place's raising and its ruin are `raising` and `ruin` events on that place; an affiliation's founding and dissolution are `founding` and `dissolution` events on that affiliation.
3116
+
3117
+ #### How far it reaches: `depth`
3118
+
3119
+ | `depth` value | the event |
3120
+ | ------------- | --------------------------------------------------------- |
3121
+ | `world` | Has to be accounted for by more than one region's history |
3122
+ | `region` | Is held by one region's history |
3123
+ | `local` | Belongs to one place, one being or one legend |
3124
+
3125
+ `depth` is set by hand and never derived. The test for `world` is not importance but reach of accounting: an event is `world` when more than one region's history has to account for it, and anything a single region can hold is that region's. A `local` event is met on the page of the place, being or legend it belongs to.
3126
+
3127
+ #### What happened, and how sure the world is: `summary` and `standing`
3128
+
3129
+ `summary` states the event plainly, in one or two sentences, with no hedging — not "it is said that", not "may have", not "legend holds". Doubt does not go in the summary. It goes in `standing`, in `accounts` and in `unresolved`.
3130
+
3131
+ | `standing` value | the world's evidence |
3132
+ | ---------------- | --------------------------------------------------------------------------- |
3133
+ | `attested` | More than one independent tradition records it |
3134
+ | `single-source` | One tradition records it, and nothing contradicts it |
3135
+ | `reconstructed` | No tradition states it; it is worked out from other records |
3136
+ | `disputed` | Traditions disagree that it happened, or on a particular the event turns on |
3137
+ | `legendary` | What is established is that a story exists, not that the thing happened |
3138
+
3139
+ `legendary` changes what `summary` describes: on a `legendary` event the summary describes the story, truthfully, because the story existing is the fact.
3140
+
3141
+ `standing` is independent of how precisely the date is written. A well-attested event can carry an approximate century, and a reconstructed one can carry an exact year because the arithmetic that places it is exact. The date's grain is in how it is written — `280` is the year, `280.25` the twenty-fifth day, `~280` around 280.
3142
+
3143
+ #### Where: `where.locus` and `where.reach`
3144
+
3145
+ `locus` is where the event physically happened — usually one place, occasionally a few, such as a battle on a border or a treaty signed in two cities. It is not the region that owns the event; no region owns one.
3146
+
3147
+ `reach` is where the event was felt, and each entry has to earn its place. **A reach entry exists only when its `how` clause can state a consequence someone in that place could notice.** "It mattered there" is not a reach entry; "the holds lost half their smiths within a generation" is. A place that felt nothing has no entry — there is no value for "unaffected", because an absent row already says so.
3148
+
3149
+ | `knowledge` value | in that place |
3150
+ | ----------------- | ------------------------------------------------------------------------------------------------------ |
3151
+ | `named` | Its own record names this event as the cause of what it felt |
3152
+ | `misattributed` | Its record names a different cause, given in `attributedTo` — the people there are wrong, not ignorant |
3153
+ | `unlinked` | The consequence is felt, and no tradition there connects it to anything |
3154
+
3155
+ `attributedTo` is written only beside `misattributed`, and names what that place blames instead: an event — a note holding one, or `note#id` — or a `lore` note, such as a people or a belief.
3156
+
3157
+ #### Who: `who`
3158
+
3159
+ `who` lives on the event, never on the participant, so a being's or a people's part in events is found by reading the events that name it rather than by listing them on its own note. A people is a legitimate participant: much of a deep past happens to peoples rather than to named individuals. An unnamed participant is not a row — a person the record cannot name is a clause in `summary` and, where who they were is open, a line in `unresolved`.
3160
+
3161
+ | `role` value | the participant |
3162
+ | ------------ | ---------------------------------------------------------------------------------------------- |
3163
+ | `actor` | Did it |
3164
+ | `victim` | Had it done to them |
3165
+ | `instrument` | Was the means by which it was done, without being its author — a host driven, a weapon wielded |
3166
+ | `witness` | Saw it, and is a source of what is known |
3167
+ | `founder` | Brought into being what the event founds |
3168
+ | `ruler` | Held the authority under which it happened, or the authority it confers |
3169
+ | `author` | Wrote or composed what the event makes — a law, a charter, a work |
3170
+ | `signatory` | Is a party bound by the agreement it records |
3171
+
3172
+ #### Names: one event, several names
3173
+
3174
+ An event known by several names in the world is one event with several names, never several events. The note's own `name` is the neutral name the chronology sorts by; `names` carries every in-world name with the people, polity, faith or place that uses it.
3175
+
3176
+ `names` and `accounts` vary independently, which is why they are two keys: a people can share an event's name and dispute what happened, or use a name of its own and agree entirely. A defeat in one chronicle and a deliverance in another is one event whose `names` differ and whose `accounts` differ.
3177
+
3178
+ #### What is believed: `accounts`, `withholds` and `unresolved`
3179
+
3180
+ Each `accounts` entry attributes one reading of the event: who holds it (`by`), what they say (`says`), how far they agree with `summary` (`agrees`), and what they decline to say (`withholds`).
3181
+
3182
+ | `agrees` value | the account |
3183
+ | -------------- | -------------------------------------------------------------------------------- |
3184
+ | `full` | Agrees with the summary |
3185
+ | `partly` | Agrees in substance and differs in particulars |
3186
+ | `disputes` | Holds that it happened, and otherwise than the summary says |
3187
+ | `denies` | Holds that it did not happen |
3188
+ | `silent` | Says nothing of it where it could — a silence stated as a fact, not an ignorance |
3189
+
3190
+ **`withholds` and `unresolved` record different things.** `withholds` is a people declining to say, which is a fact about that people and sits on that people's account. `unresolved` is the world not having settled the question, which is a fact about the world and sits on the event. Who made a weapon is `unresolved`; that the people who used it will not discuss it is `withholds`. Each `unresolved` line is a plain statement of something open, not a hedge.
3191
+
3192
+ #### Consequence: `follows`
3193
+
3194
+ `follows` is written on the later event only, and names the earlier one. Whoever writes the later event is the one who knows what it follows from, and what followed from an event is found by reading the edges that name it, so nothing is lost by writing each edge once.
3195
+
3196
+ | `followsHow` value | this event |
3197
+ | ------------------ | ----------------------------------------------- |
3198
+ | `caused` | Would not have happened without the earlier one |
3199
+ | `enabled` | Was made possible by it, not inevitable |
3200
+ | `ended` | Terminates a state the earlier one began |
3201
+ | `answered` | Is a deliberate response to it |
3202
+
3203
+ Two rules hold the graph together, and both are errors when broken:
3204
+
3205
+ - **An edge points backward in time.** The event an edge names is no later than the event writing it, comparing the two `when` dates. Two dates that both state a day compare by day; otherwise they compare by year, so a year and a day inside it are never out of order. An edge touching a `when` with no position on the axis — `unknown`, or a year-`0` date — is not ordered.
3206
+ - **The graph has no cycle.** No chain of edges leads from an event back to itself, across notes or within one.
3207
+
3208
+ A consequence is an edge, not a second event. A consequence with no date of its own is a `reach` entry, if it is felt somewhere, or a `follows` edge, if it is a later event's cause — never a new event recording the same thing twice.
3209
+
3210
+ #### Dates: `when`, `until` and `recurs`
3211
+
3212
+ An entry reads by what it authors beside `when`:
3213
+
3214
+ | authored | reads as |
3215
+ | --------------------------------- | ----------------------------------------------- |
3216
+ | `when` | happened once |
3217
+ | `when` + `until` | ran continuously from then to then |
3218
+ | `when` + `recurs` | happened then and happens still |
3219
+ | `when` + `until` + `recurs.every` | happened then, again on the period, and stopped |
3220
+
3221
+ `recurs.every` and `recurs.on` are exclusive — a period with named exceptions is written as an enumeration instead. `recurs` is refused beside a `when` of year `0`, and a being's `born` and `died` take no `recurs`. `until` is refused beside `recurs.on`, whose own last entry already bounds it.
3222
+
3223
+ **The period advances the canonical year, never the era-relative year.** There is no year `0` in era-relative numbering — era year `-1` sits immediately before era year `1` — but canonical year `0` is an ordinary integer on the continuous axis `canonicalYear` builds, so a period of whole years steps on it with no special case at an epoch crossing. Precision and approximation carry through untouched: a year-precision anchor yields year-precision occurrences, an approximate anchor's occurrences are approximate too, and an anchor inside a short intercalary month recurs on that same day in every occurrence, with no special case for the month being short. Each occurrence selects its own era by testing its position against the anchor's calendar, so a later occurrence may print in a different era than its anchor, or print bare where no count was proclaimed for that year — neither is ever a finding, since nobody authored the occurrence.
3224
+
3225
+ **Year `0` means any year.** An entry whose `when` states year `0` recurs on that day of every year — `when: "0.5"` is the fifth day of the year, in every year. The value must be quoted, for the reason every canonical date stating a day must be: an unquoted `<year>.<day>` reaches the check as a float, and a day's trailing zero is lost before a date is read. Beside a year-`0` entry, `recurs` is refused (the entry is already annual), `until` is allowed and bounds the series, and the entry carries no `canonicalYear`, era or `sort` — it cannot date its own note. A note's date is its first entry stating a real year.
3226
+
3227
+ ```yaml
3228
+ data:
3229
+ events:
3230
+ - id: anniversary
3231
+ when: "412.1"
3232
+ recurs: { every: 1 }
3233
+ summary: The city keeps the day of its founding.
3234
+ - id: harvestrite
3235
+ when: "0.286"
3236
+ until: "940.1"
3237
+ summary: The harvest rite is kept on the two-hundred-eighty-sixth day of the year.
3238
+ ```
3239
+
3240
+ The first entry is an anniversary counted from canonical day `412.1`, recurring every year with no end. The second is an autumn rite — the two-hundred-eighty-sixth day of every year — kept until canonical year 940.
3241
+
3242
+ `stated` records the date as one tradition writes it, beside the canonical `when` every event carries: `when` is what sorts and compares, and `stated.text` is what that tradition's own records say, in the calendar `stated.calendar` names.
3243
+
3244
+ #### A complete event
3245
+
3246
+ One `lore` note, `lore-fallkhazturn`, holding one event with every key written:
3247
+
3248
+ ```yaml
3249
+ shortcode: fallkhazturn
3250
+ name: { full: The Fall of Khazarturn }
3251
+ type: lore
3252
+ subType: history
3253
+ data:
3254
+ events:
3255
+ - kind: fall
3256
+ depth: world
3257
+ when: ~-2427
3258
+ summary: >-
3259
+ An outlaw takes up the Second Voice and drives the Grukar against
3260
+ Khazarturn. Every inhabitant is killed, and the Khazari seal the city as
3261
+ a tomb.
3262
+ standing: attested
3263
+ names:
3264
+ - name: The Sealing
3265
+ by: lore-khazarfolk
3266
+ gloss: what the Khazari call it
3267
+ - name: the Outlaw's Work
3268
+ by: lore-sinalefolk
3269
+ where:
3270
+ locus: [khazarturnvale]
3271
+ reach:
3272
+ - place: ironfells
3273
+ how: the holds lose half their smiths within a generation
3274
+ knowledge: named
3275
+ - place: place-grukarholm
3276
+ how: tribes arrive on the coast driven off ground they will not name
3277
+ knowledge: unlinked
3278
+ - place: place-aelwyth
3279
+ how: the joint kingdom's two peoples stop speaking
3280
+ knowledge: misattributed
3281
+ attributedTo: lore-oldcompact
3282
+ who:
3283
+ - { ref: lore-khazarfolk, role: victim }
3284
+ - { ref: lore-sinalefolk, role: actor }
3285
+ - { ref: lore-grukarfolk, role: instrument }
3286
+ follows:
3287
+ - event: place-khazarturn#raising
3288
+ how: ended
3289
+ note: the city stands two and a half millennia before it falls
3290
+ accounts:
3291
+ - by: lore-khazarfolk
3292
+ says: The Sinale did this; one of theirs held the Voice, and they never said it existed.
3293
+ agrees: partly
3294
+ withholds: whether anyone tends the city since it was sealed
3295
+ - by: lore-sinalefolk
3296
+ says: One of ours did it, and we hunted him down ourselves.
3297
+ agrees: partly
3298
+ withholds: the outlaw's name and his fate
3299
+ - by: lore-worldthalorna
3300
+ says: Something shattered the old peace in an age before memory.
3301
+ agrees: silent
3302
+ unresolved:
3303
+ - who made the Second Voice, and why neither people ever said it existed
3304
+ - what remains inside the sealed city
3305
+ sources: [lore-khazarfolk, lore-sinalefolk]
3306
+ stated: { calendar: khazarcal, text: "the 900th year of the Delving" }
3307
+ ```
3308
+
3309
+ #### A note holding two events
3310
+
3311
+ A place holds its own raising and its own fall, so each needs an `id`, and an event elsewhere names one of them by `note#id`:
3312
+
3313
+ ```yaml
3314
+ shortcode: khazarturn
3315
+ name: { full: Khazarturn }
3316
+ type: place
3317
+ subType: settlement
3318
+ data:
3319
+ events:
3320
+ - id: raising
3321
+ kind: raising
3322
+ depth: region
3323
+ when: ~-4900
3324
+ summary: The Khazari cut the first halls of Khazarturn into the valley wall.
3325
+ where: { locus: [place-khazarturn] }
3326
+ - id: sealing
3327
+ kind: ruin
3328
+ depth: local
3329
+ when: ~-2427
3330
+ summary: The Khazari seal the gates of the dead city.
3331
+ where: { locus: [place-khazarturn] }
3332
+ follows:
3333
+ - event: place-khazarturn#raising
3334
+ how: ended
3335
+ - event: lore-fallkhazturn
3336
+ how: caused
3337
+ note: the dead are laid in their own chambers before the gates are closed
3338
+ ```
3339
+
3340
+ `place-khazarturn#sealing` follows both the city's own raising, inside the same note, and `lore-fallkhazturn`, a note holding one event and so addressed by the note alone. Both edges point backward: the raising is millennia earlier, and the fall shares the sealing's year.
3341
+
2793
3342
  ### type: being
2794
3343
 
2795
3344
  Generates a living (or undead, or spirit) being.
2796
3345
 
2797
- | `data` property | Values | Description |
2798
- | --------------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
2799
- | `tokenIcon` | `Address` | What a token on the canvas wears — an `icon` address; defaults to `icon` |
2800
- | `templatePriority` | `number` | Template priority, _null_ = not a template |
2801
- | `archetypes` | `Archetype[]` | What sort of character this is. **Always an array** — character and npc require at least one; creature may omit it or write `[]`; `null` is an error. |
2802
- | `occupation` | `string` | Name of the character's occupation |
2803
- | `social` | `Map<string, unknown>` | The being's social profile |
2804
- | `stations` | `Address[]` | Name of the stations the character belongs to |
2805
- | `lore` | `Address[]` | Other lore concerning this being, such as social standing or law |
2806
- | `culture` | `Address` | Primary culture, naming a lore note with `subType: culture` |
2807
- | `homes` | `Address[]` | Place the being calls home |
2808
- | `affiliations` | `Map<Address, Membership>` | Bodies the being belongs to, keyed by Address, each entry the standing it holds there |
2809
- | `socialTies` | `Map<Address, Tie>` | Defining support and opposition, directed from this being to others |
2810
- | `gender` | `male \| female \| other` | Gender of the character |
2811
- | `species` | `Address` | Being's species (lore) |
2812
- | `born` | `date \| unknown` | When the being was born; absent, it was never born |
2813
- | `calendar` | `Address` | Calendar note used to print the being's dates |
2814
- | `died` | `date \| unknown` | When the being died; absent, it is alive |
2815
- | `age` | `34 \| ~34` | Age in years, stated only to override what `born` says; `~` marks an estimate |
2816
- | `ageYears` | `number` | Written by the compiler beside an `age` estimate — the `~` stripped; a note never authors this |
2817
- | `height` | `1.91m \| 6' 3"` | Height in metres or feet and inches |
2818
- | `weight` | `85kg \| 187 lbs` | Body weight in kilograms or pounds |
2819
- | `frame` | `scant \| light \| medium \| large \| massive` | Relative frame size |
2820
- | `appearance.eye_color` | `string` | Eye color |
2821
- | `appearance.hair_color` | `string` | Hair color |
2822
- | `appearance.skin_color` | `string` | Skin color |
2823
- | `appearance.complexion` | `string` | Complexion |
2824
- | `appearance.extra_features` | `string[]` | Extra features |
3346
+ **subType**:
3347
+
3348
+ - npc: A character meant to be encountered. It may describe a reusable template and need not be
3349
+ a singular individual.
3350
+ - character: A detailed, playable, singular individual.
3351
+ - creature: Any being that is neither a character nor an NPC.
3352
+
3353
+ See [a being's subtype describes the subject](#a-beings-subtype-describes-the-subject).
3354
+
3355
+ | `data` property | Values | Description |
3356
+ | ------------------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
3357
+ | `tokenIcon` | `Address` | What a token on the canvas wears — an `icon` address; defaults to `icon` |
3358
+ | `templatePriority` | `number` | Template priority, _null_ = not a template |
3359
+ | `archetypes` | `Archetype[]` | What sort of character this is. **Always an array** — character and npc require at least one; creature may omit it or write `[]`; `null` is an error. |
3360
+ | `occupation` | `string` | Name of the character's occupation |
3361
+ | `stations` | `Address[]` | Name of the stations the character belongs to |
3362
+ | `lore` | `Address[]` | Other lore concerning this being, such as social standing or law |
3363
+ | `culture` | `Address` | Primary culture, naming a lore note with `subType: culture` |
3364
+ | `homes` | `Address[]` | Place the being calls home |
3365
+ | `affiliations` | `Map<Address, Membership>` | Bodies the being belongs to, keyed by Address, each entry the standing it holds there |
3366
+ | `affiliations.<Address>.rank` | `integer`, required | The level on that body's own `governance.ranks` ladder; `1` is an ordinary member, `0` someone cast out |
3367
+ | `affiliations.<Address>.office` | `string` | A post that body names in its `governance.offices`, where the being holds one |
3368
+ | `socialTies` | `Map<Address, Tie>` | Defining support and opposition, directed from this being to others |
3369
+ | `gender` | `male \| female \| other` | Gender of the character |
3370
+ | `species` | `Address` | Being's species (lore) |
3371
+ | `born` | `date \| unknown` | When the being was born; absent, it was never born |
3372
+ | `calendar` | `Address` | Calendar note used to print the being's dates |
3373
+ | `died` | `date \| unknown` | When the being died; absent, it is alive |
3374
+ | `age` | `34 \| ~34` | Age in years, stated only to override what `born` says; `~` marks an estimate |
3375
+ | `ageYears` | `number` | Written by the compiler beside an `age` estimate — the `~` stripped; a note never authors this |
3376
+ | `height` | `1.91m \| 6' 3"` | Height in metres or feet and inches |
3377
+ | `weight` | `85kg \| 187 lbs` | Body weight in kilograms or pounds |
3378
+ | `frame` | `scant \| light \| medium \| large \| massive` | Relative frame size |
3379
+ | `appearance.eye_color` | `string` | Eye color |
3380
+ | `appearance.hair_color` | `string` | Hair color |
3381
+ | `appearance.skin_color` | `string` | Skin color |
3382
+ | `appearance.complexion` | `string` | Complexion |
3383
+ | `appearance.extra_features` | `string[]` | Extra features |
2825
3384
 
2826
3385
  Author `data.height` as a string of decimal metres (`1.91m` or `1.91 m`) or
2827
3386
  whole feet with optional inches (`6'`, `6'3"`, or `6' 3"`). Inches must be
@@ -2890,9 +3449,18 @@ each an error naming the file, line and column — so a renamed rung or a rename
2890
3449
  post fails on every being pointing at it. Naming one body twice, by its short
2891
3450
  and full Address, still names one body and is an error.
2892
3451
 
2893
- The infobox prints the standing closing on its body — `War Chief, Hárár, of
2894
- Vrystwald Tribes` — and links an office to the description the body itself
2895
- declares, so recording the post needs no note about the post.
3452
+ The infobox prints one line per membership, in the order the note writes them,
3453
+ in a section of its own titled **Affiliations**: the office where one is held, then the rung's
3454
+ title with its level in parentheses, then the body — `War Chief, Hárár (5), of
3455
+ Vrystwald Tribes`, or `Hárár (5), of Vrystwald Tribes` with no office. The title
3456
+ is read from the body's own `governance.ranks`; where the body declares no rung
3457
+ at that level, or its ladder is not available, the rung reads as `Rank 5` —
3458
+ `Rank 5, of Vrystwald Tribes`. The body's name links to its page, and is plain
3459
+ text where it publishes none. A membership written in the list form, with no
3460
+ standing, is the body's name alone. The lines are the same on the website, in
3461
+ a Foundry journal and in the book. On the body's own page each office is a row
3462
+ anchored by its name, so the post a being holds is described where the body
3463
+ declares it.
2896
3464
 
2897
3465
  For SoHL, a being embeds one affiliation item per entry: `rank` **is** that
2898
3466
  item's `system.level` and `office` its `system.office`. A standing is a fact
@@ -3075,7 +3643,7 @@ An embedded custom item writes its identity in `system.shortcode`; a top-level `
3075
3643
  #### An entry's art
3076
3644
 
3077
3645
  An entry is an item in every respect but where it is written, so it carries art
3078
- by the two rules [an item note](#the-four-art-slots) does. It names an `icon`
3646
+ by the two rules [an item note](#the-art-slots) does. It names an `icon`
3079
3647
  address under its own `data:`, and that resolves into the embedded document's
3080
3648
  `img`:
3081
3649
 
@@ -3324,22 +3892,35 @@ rank names the standing, and the standing says.
3324
3892
 
3325
3893
  **Standing**: aligned, unaligned, rival, nemesis
3326
3894
 
3327
- | `data` property | Values | Description |
3328
- | -------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
3329
- | `templatePriority` | `number` | Template priority, _null_ = not a template |
3330
- | `demonym` | `string` | What a member of this affiliation is called (a Vylarian) |
3331
- | `epithet` | `string` | The by-name it is known by — a god's, an order's, a company's |
3332
- | `symbol` | `string` | Its emblem in words: a feather atop a golden scale, a chisel carving a star |
3333
- | `governance.model` | `GovernanceModel` | Type of government structure, if applicable |
3334
- | `governance.summary` | `string` | summary of the governance situation |
3335
- | `governance.ranks` | `Rank[]` | The ranks available to members of the affiliation |
3336
- | `governance.offices` | `Map<name, description \| {description, holders}>` | Official offices and their dated holders |
3337
- | `seat` | `Address` | Where the affiliation's authority sits |
3338
- | `population` | `number` | Number of people in the affiliation (precision 2 significant digits). |
3339
- | `economy` | `Address[]` | Economic life: `affiliation` or `lore` Addresses, with an explicit type and no default |
3340
- | `lore` | `Address[]` | Lore concerning it — the peoples it draws on, the god a faith venerates, its law, its calendar |
3341
- | `parents` | `Address[]` | Affiliations that this affiliation is subordinate to |
3342
- | `relations` | `Map<Address, Standing>` | Standing with other affiliations, keyed by the other body's Address |
3895
+ | `data` property | Values | Description |
3896
+ | ----------------------------------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
3897
+ | `templatePriority` | `number` | Template priority, _null_ = not a template |
3898
+ | `events` | event entries — see [Events](#events) | What happened to or at this subject: dated, attributed events |
3899
+ | `demonym` | `string` | What a member of this affiliation is called (a Vylarian) |
3900
+ | `epithet` | `string` | The by-name it is known by — a god's, an order's, a company's |
3901
+ | `symbol` | `string` | Its emblem in words: a feather atop a golden scale, a chisel carving a star |
3902
+ | `governance.model` | `GovernanceModel` | Type of government structure, if applicable |
3903
+ | `governance.summary` | `string` | summary of the governance situation |
3904
+ | `governance.ranks` | `Rank[]` | The ranks available to members of the affiliation |
3905
+ | `governance.ranks[].level` | `integer`, required | The rung's position on this body's ladder; a member's `rank` names it |
3906
+ | `governance.ranks[].title` | `string`, required | What the standing is called |
3907
+ | `governance.ranks[].description` | `string`, required | What the standing is |
3908
+ | `governance.ranks[].lore` | `Address` | The `law` lore note stating what the standing is, shared with every body that confers it |
3909
+ | `governance.offices` | `Map<name, description \| {description, holders}>` | Official offices and their dated holders |
3910
+ | `governance.offices.<name>` | `string` or `{ description, holders }` | One office, keyed by its name: its description, or a map of description and holders |
3911
+ | `governance.offices.<name>.description` | `string`, required | What the office is |
3912
+ | `governance.offices.<name>.holders` | `{ being, start?, end?, contested? }[]`, required | Who has held the office, each with the dates of the term |
3913
+ | `governance.offices.<name>.holders[].being` | `Address`, required | The `being` who held it |
3914
+ | `governance.offices.<name>.holders[].start` | `date` | When the term began; omitted, it began before anything recorded |
3915
+ | `governance.offices.<name>.holders[].end` | `date` | When the term ended; omitted, the being holds the office now |
3916
+ | `governance.offices.<name>.holders[].contested` | `boolean` | `true` where the term may overlap another holder's |
3917
+ | `seat` | `Address` | Where the affiliation's authority sits |
3918
+ | `population` | `number` | Number of people in the affiliation (precision 2 significant digits). |
3919
+ | `economy` | `Address[]` | Economic life: `affiliation` or `lore` Addresses, with an explicit type and no default |
3920
+ | `lore` | `Address[]` | Lore concerning it — the peoples it draws on, the god a faith venerates, its law, its calendar |
3921
+ | `parents` | `Address[]` | Affiliations that this affiliation is subordinate to |
3922
+ | `relations` | `Map<Address, Standing>` | Standing with other affiliations, keyed by the other body's Address |
3923
+ | `relations.<Address>` | `aligned`, `unaligned`, `rival` or `nemesis` | The standing this body holds toward that one; any other value is an error at the value |
3343
3924
 
3344
3925
  **A faith tradition is not its god.** An `affiliation` of subType
3345
3926
  `faithtradition` is a _religion_ — a practice, with an ordained priesthood, a
@@ -3394,7 +3975,7 @@ data:
3394
3975
  - { being: being-mara, start: "datefrom vrcal 2 Lusenar 725 VR" }
3395
3976
  ```
3396
3977
 
3397
- **Governed places are derived from place notes.** Each place names one governing affiliation in `data.government`. The website writes the body's `governed_places` list by resolving those explicit references across local notes and fetched indexes. Each entry is `{ title, url, type, subType }`, sorted by `subType` then `title`; an empty list is omitted. No affiliation-side list supplies government, and neither geographic containment nor organizational parents expands it.
3978
+ **Governed places are derived from place notes.** Each place names one governing affiliation in `data.government`. The affiliation's **Governed places** [generated section](#generated-sections) lists the places whose explicit references resolve to it, across local notes and fetched indexes, grouped by kind; with none, it has no such section. No affiliation-side list supplies government, and neither geographic containment nor organizational parents expands it.
3398
3979
 
3399
3980
  If `sohl` is present, this becomes an `affiliation` item.
3400
3981
 
@@ -3533,13 +4114,15 @@ for traumas produced by the affliction's outcome. The optional
3533
4114
 
3534
4115
  Note: `data.quantity` may not be specified. Quantity is always 1.
3535
4116
 
3536
- | `data` property | Values | Description |
3537
- | ------------------ | -------- | ------------------------------------------ |
3538
- | `templatePriority` | `number` | Template priority, _null_ = not a template |
3539
- | `weight` | `number` | Gear weight |
3540
- | `value` | `number` | Gear value |
3541
- | `quality` | `number` | Gear quality |
3542
- | `durability` | `number` | Gear durability |
4117
+ | `data` property | Values | Description |
4118
+ | ------------------ | ---------------- | ----------------------------------------------------------------------------- |
4119
+ | `templatePriority` | `number` | Template priority, _null_ = not a template |
4120
+ | `weight` | `number` | Gear weight |
4121
+ | `value` | `number` | Gear value |
4122
+ | `quality` | `number` | Gear quality |
4123
+ | `durability` | `number` | Gear durability |
4124
+ | `made` | an event Address | The event in which it was made — `lore-forging`, or `place-ironfells#raising` |
4125
+ | `lost` | an event Address | The event in which it was lost — `lore-flood`, or `place-ironfells#sack` |
3543
4126
 
3544
4127
  If a `sohl` property is present, a SoHL item of type "armorgear" is created.
3545
4128
 
@@ -3552,6 +4135,16 @@ The note type is `armorgear` in both systems.
3552
4135
  | `data.quality` | `system.qualityBase` | NA |
3553
4136
  | `data.durability` | `system.durabilityBase` | NA |
3554
4137
 
4138
+ Every gear type — `armorgear`, `concoctiongear`, `containergear`, `miscgear`,
4139
+ `projectilegear` and `weapongear` — may name the events of the thing's history:
4140
+ `made`, the event in which it was made, and `lost`, the event in which it was
4141
+ lost. Each is an Address of exactly one [event](#events): `note#id`, or a note
4142
+ holding one event. A bare shortcode is read as a `lore` note, so
4143
+ `made: forging` is `lore-forging`. Naming a note that holds several events
4144
+ without an `id`, a note holding none, an anchor the note does not declare, or
4145
+ a `prose` anchor is an error at that key. Neither reaches a system field, an
4146
+ infobox row or a page: each is a fact a content table can read.
4147
+
3555
4148
  ### type: armorlocation
3556
4149
 
3557
4150
  | `data` property | Values | Description |
@@ -3583,16 +4176,18 @@ if a `sohl` property is present, a SoHL item of type "attribute" is created.
3583
4176
  - exotic: A complex and valuable concoction, often a mixture of different herbs and/or chemicals, with medicinal or other unique properties or effects, but not magical in nature.
3584
4177
  - elixir: An arcane alchemical concoction of great power.
3585
4178
 
3586
- | `data` property | Values | Description |
3587
- | ------------------ | ------------------------------- | ------------------------------------------------- |
3588
- | `templatePriority` | `number` | Template priority, _null_ = not a template |
3589
- | `weight` | `number` | Gear weight |
3590
- | `value` | `number` | Gear value |
3591
- | `quality` | `number` | Gear quality |
3592
- | `durability` | `number` | Gear durability |
3593
- | `quantity` | `number` | Gear quantity (default: 1) |
3594
- | `potency` | `na \| mild \| strong \| great` | Concoction Potency (mundane/exotic concoctions) |
3595
- | `strength` | `number` | Strength: higher the number, greater the strength |
4179
+ | `data` property | Values | Description |
4180
+ | ------------------ | ------------------------------- | ----------------------------------------------------------------------------- |
4181
+ | `templatePriority` | `number` | Template priority, _null_ = not a template |
4182
+ | `weight` | `number` | Gear weight |
4183
+ | `value` | `number` | Gear value |
4184
+ | `quality` | `number` | Gear quality |
4185
+ | `durability` | `number` | Gear durability |
4186
+ | `made` | an event Address | The event in which it was made — `lore-forging`, or `place-ironfells#raising` |
4187
+ | `lost` | an event Address | The event in which it was lost — `lore-flood`, or `place-ironfells#sack` |
4188
+ | `quantity` | `number` | Gear quantity (default: 1) |
4189
+ | `potency` | `na \| mild \| strong \| great` | Concoction Potency (mundane/exotic concoctions) |
4190
+ | `strength` | `number` | Strength: higher the number, greater the strength |
3596
4191
 
3597
4192
  if a `sohl` property is present, a SoHL item of type "concoctiongear" is created.
3598
4193
 
@@ -3611,14 +4206,16 @@ if a `sohl` property is present, a SoHL item of type "concoctiongear" is created
3611
4206
 
3612
4207
  Note: `data.quantity` may not be specified; quantity is always set to 1.
3613
4208
 
3614
- | `data` property | Values | Description |
3615
- | ------------------ | -------- | ------------------------------------------ |
3616
- | `templatePriority` | `number` | Template priority, _null_ = not a template |
3617
- | `weight` | `number` | Gear weight |
3618
- | `value` | `number` | Gear value |
3619
- | `quality` | `number` | Gear quality |
3620
- | `durability` | `number` | Gear durability |
3621
- | `capacity` | `number` | HM3 container capacity (in lbs) |
4209
+ | `data` property | Values | Description |
4210
+ | ------------------ | ---------------- | ----------------------------------------------------------------------------- |
4211
+ | `templatePriority` | `number` | Template priority, _null_ = not a template |
4212
+ | `weight` | `number` | Gear weight |
4213
+ | `value` | `number` | Gear value |
4214
+ | `quality` | `number` | Gear quality |
4215
+ | `durability` | `number` | Gear durability |
4216
+ | `made` | an event Address | The event in which it was made — `lore-forging`, or `place-ironfells#raising` |
4217
+ | `lost` | an event Address | The event in which it was lost — `lore-flood`, or `place-ironfells#sack` |
4218
+ | `capacity` | `number` | HM3 container capacity (in lbs) |
3622
4219
 
3623
4220
  if a `sohl` property is present, a SoHL item of type "containergear" is created.
3624
4221
 
@@ -3636,14 +4233,16 @@ SoHL reads a container’s capacity in pounds from `sohl.maxCapacity`.
3636
4233
 
3637
4234
  ### type: miscgear
3638
4235
 
3639
- | `data` property | Values | Description |
3640
- | ------------------ | -------- | ------------------------------------------ |
3641
- | `templatePriority` | `number` | Template priority, _null_ = not a template |
3642
- | `weight` | `number` | Gear weight |
3643
- | `value` | `number` | Gear value |
3644
- | `quality` | `number` | Gear quality |
3645
- | `durability` | `number` | Gear durability |
3646
- | `quantity` | `number` | HM3 gear quantity (default: 1) |
4236
+ | `data` property | Values | Description |
4237
+ | ------------------ | ---------------- | ----------------------------------------------------------------------------- |
4238
+ | `templatePriority` | `number` | Template priority, _null_ = not a template |
4239
+ | `weight` | `number` | Gear weight |
4240
+ | `value` | `number` | Gear value |
4241
+ | `quality` | `number` | Gear quality |
4242
+ | `durability` | `number` | Gear durability |
4243
+ | `made` | an event Address | The event in which it was made — `lore-forging`, or `place-ironfells#raising` |
4244
+ | `lost` | an event Address | The event in which it was lost — `lore-flood`, or `place-ironfells#sack` |
4245
+ | `quantity` | `number` | HM3 gear quantity (default: 1) |
3647
4246
 
3648
4247
  if a `sohl` property is present, a SoHL item of type "miscgear" is created.
3649
4248
 
@@ -3753,14 +4352,16 @@ the item’s base mastery and level from `sohl.masteryLevelBase` and
3753
4352
  - dart
3754
4353
  - other
3755
4354
 
3756
- | `data` property | Values | Description |
3757
- | ------------------ | -------- | ------------------------------------------ |
3758
- | `templatePriority` | `number` | Template priority, _null_ = not a template |
3759
- | `weight` | `number` | Gear weight |
3760
- | `value` | `number` | Gear value |
3761
- | `quality` | `number` | Gear quality |
3762
- | `durability` | `number` | Gear durability |
3763
- | `quantity` | `number` | HM3 gear quantity (default: 1) |
4355
+ | `data` property | Values | Description |
4356
+ | ------------------ | ---------------- | ----------------------------------------------------------------------------- |
4357
+ | `templatePriority` | `number` | Template priority, _null_ = not a template |
4358
+ | `weight` | `number` | Gear weight |
4359
+ | `value` | `number` | Gear value |
4360
+ | `quality` | `number` | Gear quality |
4361
+ | `durability` | `number` | Gear durability |
4362
+ | `made` | an event Address | The event in which it was made — `lore-forging`, or `place-ironfells#raising` |
4363
+ | `lost` | an event Address | The event in which it was lost — `lore-flood`, or `place-ironfells#sack` |
4364
+ | `quantity` | `number` | HM3 gear quantity (default: 1) |
3764
4365
 
3765
4366
  if a `sohl` property is present, a SoHL item of type "projectilegear" is created.
3766
4367
 
@@ -3876,13 +4477,15 @@ build.
3876
4477
 
3877
4478
  Note: `data.quantity` may not be specified. Quantity is always 1.
3878
4479
 
3879
- | `data` property | Values | Description |
3880
- | ------------------ | -------- | ------------------------------------------ |
3881
- | `templatePriority` | `number` | Template priority, _null_ = not a template |
3882
- | `weight` | `number` | Gear weight |
3883
- | `value` | `number` | Gear value |
3884
- | `quality` | `number` | Gear quality |
3885
- | `durability` | `number` | Gear durability |
4480
+ | `data` property | Values | Description |
4481
+ | ------------------ | ---------------- | ----------------------------------------------------------------------------- |
4482
+ | `templatePriority` | `number` | Template priority, _null_ = not a template |
4483
+ | `weight` | `number` | Gear weight |
4484
+ | `value` | `number` | Gear value |
4485
+ | `quality` | `number` | Gear quality |
4486
+ | `durability` | `number` | Gear durability |
4487
+ | `made` | an event Address | The event in which it was made — `lore-forging`, or `place-ironfells#raising` |
4488
+ | `lost` | an event Address | The event in which it was lost — `lore-flood`, or `place-ironfells#sack` |
3886
4489
 
3887
4490
  if a `sohl` property is present, a SoHL item of type "weapongear" is created,
3888
4491
  carrying every strike mode the weapon has — melee and missile alike — on
@@ -3926,50 +4529,73 @@ the setting itself, rather than instructions or other apparatus for the GM.
3926
4529
  which covers the _reckoning_ — a festival's date is calendar and the festival is not, and a
3927
4530
  tournament is not a matter of time-reckoning at all — and from `culture`, which is a grouping
3928
4531
  of people rather than an occasion they attend.
3929
-
3930
- | `data` property | Values | Description |
3931
- | ----------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
3932
- | `epoch` | canonical `<year>.<day>` | The canonical day that equals calendar year 1, day 1 |
3933
- | `months` | `{ name, abbreviation?, days }[]` | Ordered months; their days sum to the world's year |
3934
- | `weekdays` | `{ name, abbreviation? }[]` | Ordered week days, indexed from zero; weeks run continuously |
3935
- | `seasons` | `{ name, abbreviation?, start }[]` | Seasons starting on one-based days of year |
3936
- | `namedDays` | `{ name, abbreviation?, day }[]` | Names assigned to one-based days of year |
3937
- | `eras` | `{ shortcode, name, abbreviation?, marker?, proclaimedBy?, start, label? }[]` | Year counts; `start` is `null` or an in-calendar year |
3938
- | `formats` | map of names to Calendaria patterns | Named date formats; `std` is the preferred default |
3939
- | `events` | `{ when, until?, recurs? }[]` | This note's dated occurrences, each with its own relationships and chronicle fields |
3940
- | `events[].when` | a date, or `"0.<day>"` | The occurrence's anchor and first instance — required |
3941
- | `events[].until` | a date | Where the occurrence ran to, or where a recurring series stopped |
3942
- | `events[].recurs` | `{ every }` or `{ on }` | How further occurrences are found, absent for a one-time occurrence |
3943
- | `events[].recurs.every` | whole number of years, 1 or more | A period counted on the canonical axis from `when` |
3944
- | `events[].recurs.on` | list of dates, strictly increasing, each later than `when` | Recorded occurrences beyond the first, in place of a period |
3945
-
3946
- `data.events` is available on every `lore` subType. Each entry's `kind`, `depth`, `summary`, `sources`, `standing`, `accounts`, `who`, `where`, `unresolved`, `follows` and `names` hold its chronicle detail; their shapes belong to whatever design governs chronicle records, and this format only asks that they sit inside an entry. The shared format checks `when`, `until` and `recurs`; a content package can check the rest. `events` itself does not appear as an infobox row, but a recurring entry's computed next occurrence does.
3947
-
3948
- An entry reads by what it authors beside `when`:
3949
-
3950
- | authored | reads as |
3951
- | --------------------------------- | ----------------------------------------------- |
3952
- | `when` | happened once |
3953
- | `when` + `until` | ran continuously from then to then |
3954
- | `when` + `recurs` | happened then and happens still |
3955
- | `when` + `until` + `recurs.every` | happened then, again on the period, and stopped |
3956
-
3957
- `recurs.every` and `recurs.on` are exclusive — a period with named exceptions is written as an enumeration instead. `recurs` is refused beside `born` or `died`, and beside a `when` of year `0`. `until` is refused beside `recurs.on`, whose own last entry already bounds it.
3958
-
3959
- **The period advances the canonical year, never the era-relative year.** There is no year `0` in era-relative numbering — era year `-1` sits immediately before era year `1` — but canonical year `0` is an ordinary integer on the continuous axis `canonicalYear` builds, so a period of whole years steps on it with no special case at an epoch crossing. Precision and approximation carry through untouched: a year-precision anchor yields year-precision occurrences, an approximate anchor's occurrences are approximate too, and an anchor inside a short intercalary month recurs on that same day in every occurrence, with no special case for the month being short. Each occurrence selects its own era by testing its position against the anchor's calendar, so a later occurrence may print in a different era than its anchor, or print bare where no count was proclaimed for that year — neither is ever a finding, since nobody authored the occurrence.
3960
-
3961
- **Year `0` means any year.** An entry whose `when` states year `0` recurs on that day of every year — `when: "0.5"` is the fifth day of the year, in every year. The value must be quoted, for the reason every canonical date stating a day must be: an unquoted `<year>.<day>` reaches the check as a float, and a day's trailing zero is lost before a date is read. Beside a year-`0` entry, `recurs` is refused (the entry is already annual), `until` is allowed and bounds the series, and the entry carries no `canonicalYear`, era or `sort` — it cannot date its own note. A note's date is its first entry stating a real year.
4532
+ - literature: A work a people composes and keeps — an epic, saga, poem, legend, hymn or
4533
+ chronicle, told, sung or written. Held apart from `history`, which states what happened: a
4534
+ legend is literature whether or not its events took place, and a chronicle is literature as a
4535
+ work even where its events are also history.
4536
+
4537
+ Each note a work names in `data.subjects` lists that work on its own site page, under **In
4538
+ song and story**, with the work's `form` beside its title; the subject note writes nothing.
4539
+ Each subject may name one event, as `place-ironfells#sack`: the anchor must be an `event` anchor
4540
+ the note declares, and the work lists on the page of the note that holds the event.
4541
+ A work in a fetched index lists on this package's pages when that index carries its
4542
+ `subjects`.
3962
4543
 
3963
4544
  ```yaml
4545
+ shortcode: burningsaga
4546
+ name: { full: The Saga of the Burning }
4547
+ type: lore
4548
+ subType: literature
3964
4549
  data:
3965
- events:
3966
- - when: 412.1
3967
- recurs: { every: 1 }
3968
- - when: "0.286"
3969
- until: 940.1
4550
+ culture: lore-ironfolk
4551
+ form: saga
4552
+ subjects: [place-ironfells#sack, place-east, lore-fords]
4553
+ language: skill-ironspeech
3970
4554
  ```
3971
4555
 
3972
- The first entry is an anniversary counted from canonical day `412.1`, recurring every year with no end. The second is an autumn rite — the two-hundred-eighty-sixth day of every year — that was kept until canonical year 940 and no longer is.
4556
+ The saga lists under **In song and story** on `place-ironfells`, which holds the
4557
+ sack, on `place-east` and on `lore-fords`.
4558
+
4559
+ Calendar fields are written only on a `calendar` note, and `culture`, `form`, `subjects` and
4560
+ `language` only on a `literature` note; written on any other lore subType, each is an error at
4561
+ its own key.
4562
+
4563
+ | `data` property | Values | Description |
4564
+ | -------------------------- | ----------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
4565
+ | `epoch` | canonical `<year>.<day>` | The canonical day that equals calendar year 1, day 1 |
4566
+ | `months` | `{ name, abbreviation?, days }[]` | Ordered months; their days sum to the world's year |
4567
+ | `months[].name` | `string`, required | The month's name |
4568
+ | `months[].abbreviation` | `string` | Its short form, for a compact date |
4569
+ | `months[].days` | `integer`, required | How many days the month holds |
4570
+ | `weekdays` | `{ name, abbreviation? }[]` | Ordered week days, indexed from zero; weeks run continuously |
4571
+ | `weekdays[].name` | `string`, required | The day's name |
4572
+ | `weekdays[].abbreviation` | `string` | Its short form, for a compact date |
4573
+ | `seasons` | `{ name, abbreviation?, start }[]` | Seasons starting on one-based days of year |
4574
+ | `seasons[].name` | `string`, required | The season's name |
4575
+ | `seasons[].abbreviation` | `string` | Its short form, for a compact date |
4576
+ | `seasons[].start` | `integer`, required | The one-based day of the year it begins; starts increase down the list |
4577
+ | `namedDays` | `{ name, abbreviation?, day }[]` | Names assigned to one-based days of year |
4578
+ | `namedDays[].name` | `string`, required | The day's name |
4579
+ | `namedDays[].abbreviation` | `string` | Its short form, for a compact date |
4580
+ | `namedDays[].day` | `integer`, required | The one-based day of the year it names, distinct within the calendar |
4581
+ | `eras` | `{ shortcode, name, abbreviation?, marker?, proclaimedBy?, start, label? }[]` | Year counts; `start` is `null` or an in-calendar year |
4582
+ | `eras[].shortcode` | `string`, required | The era's own segment of `<calendar>.<era>`, unique within the calendar |
4583
+ | `eras[].name` | `string`, required | The era's name |
4584
+ | `eras[].marker` | `string` | Uppercase letters and digits, beginning with a letter, unique across the corpus; an authored date names the era by it |
4585
+ | `eras[].abbreviation` | `string` | Its short form, for a compact date |
4586
+ | `eras[].proclaimedBy` | `Address` | The body that began the reckoning |
4587
+ | `eras[].start` | `null` or `integer`, required | The calendar year the era begins; `null` for the era before year 1 |
4588
+ | `eras[].label` | `string` or `{ after?, before? }` | How a date in the era reads, around one `{date}` slot; a string is `after` |
4589
+ | `eras[].label.after` | `string` | How a date from the era's start reads, with exactly one `{date}` |
4590
+ | `eras[].label.before` | `string` | How a date before the era's start reads, with exactly one `{date}` |
4591
+ | `formats` | map of names to Calendaria patterns | Named date formats; `std` is the preferred default |
4592
+ | `culture` | `Address` | `literature` only: the people whose work it is, naming a lore note with `subType: culture` |
4593
+ | `form` | `string` | `literature` only: the kind of work in its people's own terms — `epic`, `saga`, `praise-song`, `elegy`. Free text |
4594
+ | `subjects` | `Address[]` | `literature` only: the beings, places, gods and other notes the work concerns, and any event, as `note#id` |
4595
+ | `language` | `Address` | `literature` only: the tongue it is composed in, naming a skill note with `subType: language` |
4596
+ | `events` | event entries — see [Events](#events) | What happened to or at this subject: dated, attributed events |
4597
+
4598
+ `data.events` is available on every `lore` subType, and is described in full under [Events](#events).
3973
4599
 
3974
4600
  #### Calendar note structure
3975
4601
 
@@ -4072,39 +4698,40 @@ Braced custom forms such as `{era}` are equivalent to bracketed custom forms. A
4072
4698
 
4073
4699
  ### type: map
4074
4700
 
4075
- A map note has its own prose and a Foundry Scene. A map can depict a place or an encounter. Several maps can depict the same place; the map names that place with `sohl.place`, while the place note does not list its maps.
4701
+ A map note has its own prose and a Foundry Scene. A map can depict a place or an encounter. Several maps can depict the same place; the map names that place with `data.place`, while the place note does not list its maps.
4702
+
4703
+ **The Scene is made in Foundry.** Walls, lights, sounds, regions, levels and pins are drawn in Foundry's Scene editor, exported, and carried by the note at `data.scene`. The build passes the Scene through: it applies `data.fixup`, binds pins marked `#anchor` to this note's pages, and checks nothing else inside it.
4076
4704
 
4077
4705
  **subType**:
4078
4706
 
4079
- - `battlemap`: A tactical Scene built in Foundry.
4080
- - `localmap`: A settlement or local-area Scene built in Foundry.
4081
- - `regionalmap`: A large-scale chart with an authored image and scale.
4082
- - `totm`: A gridless image Scene for theatre-of-the-mind play.
4083
-
4084
- | `data` property | Values | Description |
4085
- | ----------------- | ------------ | ---------------------------------------------------------- |
4086
- | `scene` | object | Exported Foundry Scene for battle and local maps |
4087
- | `fixup` | object[] | Asset address replacements in an exported Scene |
4088
- | `bgImage` | Address | Background image for regional and theatre-of-the-mind maps |
4089
- | `scale` | object | Regional distance and unit per grid unit |
4090
- | `dimensions` | `[int, int]` | Optional shared dimensions metadata |
4091
- | `pxPerGrid` | number | Optional shared grid size metadata |
4092
- | `navName` | string | Short Scene navigation name |
4093
- | `levelName` | string | Embedded Level name |
4094
- | `backgroundColor` | string | Colour outside the art |
4095
- | `overlay` | string | Foreground art path |
4096
- | `walls` | object | Regional wall geometry |
4097
- | `doors` | object | Regional door geometry |
4098
- | `lights` | object | Regional light geometry |
4099
- | `tiles` | object | Regional tile geometry |
4100
- | `sounds` | object | Regional sound geometry |
4101
- | `regions` | object | Regional region geometry |
4102
- | `notes` | object | Regional pin geometry |
4103
- | `place` | Address | Depicted place, when one exists |
4104
-
4105
- #### Battle and local maps
4106
-
4107
- Author the Scene in Foundry, export it, convert the export to YAML, and put the resulting object at `data.scene`. Preserve its walls, lights, tiles, regions, levels, environment, flags, and canvas settings. The export can name art from another Foundry package; that path is used as authored in Foundry. The Scene needs positive whole-number `width` and `height`, at least one Level, a valid `initialLevel` when present, and a unique 16-character `_id` on each embedded document. The build derives the top-level Scene `_id` from the map note, adds compendium keys and build metadata, and otherwise preserves the exported fields.
4707
+ - `battlemap`: A tactical encounter map.
4708
+ - `localmap`: A settlement or local-area map.
4709
+ - `regionalmap`: A large-scale chart.
4710
+ - `totm`: A single picture for theatre-of-the-mind play.
4711
+
4712
+ A subtype says what kind of map the note is. Every subtype carries an exported Scene.
4713
+
4714
+ | `data` property | Values | Description |
4715
+ | --------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
4716
+ | `scene` | object | **Keys not declared here:** the Foundry Scene document, as exported. Its keys are Foundry's Scene schema and are not checked; the build passes the Scene through, and the book reads its levels' background images — see [Exporting the Scene](#exporting-the-scene) |
4717
+ | `fixup` | `{ path, type, value }[]` | Asset address replacements in the exported Scene |
4718
+ | `fixup[].path` | `string`, required | The exported field to replace, as a property path from `data.scene` |
4719
+ | `fixup[].type` | `address`, required | What `value` is |
4720
+ | `fixup[].value` | `Address`, required | The asset Address whose path replaces the exported one |
4721
+ | `place` | Address | Depicted place, when one exists |
4722
+
4723
+ `data.scene` must be an object, and that is the only check made of it: its keys
4724
+ are Foundry's Scene schema. A map note declares nothing under its system block.
4725
+
4726
+ #### Exporting the Scene
4727
+
4728
+ Build the Scene in Foundry, export it, convert the export to YAML, and put the
4729
+ resulting object at `data.scene`. Its walls, lights, tiles, sounds, regions,
4730
+ levels, environment, flags and canvas settings are preserved as exported. The
4731
+ export can name art from another Foundry package; that path is used as authored
4732
+ in Foundry. The build derives the top-level Scene `_id` from the map note, adds
4733
+ compendium keys to each embedded document that carries an `_id`, adds build
4734
+ metadata, and otherwise preserves the exported fields.
4108
4735
 
4109
4736
  A pin's `text` can contain `#anchor`, where the map note has a heading such as `# Big Bad Wolf {#myanchor1}`. With `text: '#myanchor1'`, the compiled pin opens the JournalEntry and page generated from this map note and displays **Big Bad Wolf**. Its position, icon, other settings, and embedded `_id` remain as exported. A missing anchor is a build error. Pins whose text does not use `#anchor` retain their exported text and references.
4110
4737
 
@@ -4138,7 +4765,7 @@ data:
4138
4765
  name: Wolf Den Scene
4139
4766
  width: 1900
4140
4767
  height: 2600
4141
- grid: { type: 1 size=100 distance: 5 units: ft }
4768
+ grid: { type: 1, size: 100, distance: 5, units: ft }
4142
4769
  initialLevel: defaultLevel0000
4143
4770
  levels:
4144
4771
  - { _id: defaultLevel0000, background: { src: modules/maps/den.webp } }
@@ -4148,20 +4775,15 @@ data:
4148
4775
  # Big Bad Wolf {#myanchor1}
4149
4776
  ```
4150
4777
 
4151
- When the Scene has pins, its Adventure bundle carries the Scene and the JournalEntry generated from its Markdown. Importing that bundle preserves the IDs the pins address.
4152
-
4153
- #### Regional maps
4154
-
4155
- A `regionalmap` uses `data.bgImage`, an image Address, and `sohl.dimensions: [width, height]` plus `sohl.pxPerGrid` to build a gridless Scene. `data.scale: {distance: positive number, unit: nonempty string}` sets the distance per grid unit. Its shared `data` fields can also name `overlay`, `backgroundColor`, `levelName`, `navName`, `walls`, `doors`, `lights`, `tiles`, `sounds`, `regions`, and `notes`; the latter geometry uses the map-note conventions described in the SoHL map authoring guide. `data.scene` is not used for a regional map.
4156
-
4157
- An SVG `data.bgImage` remains vector art on the site and in the book. The Foundry build stages a PNG at the note's stated dimensions with the installed SVG renderer; the source SVG is unchanged. Its aspect ratio must match the stated dimensions. A selected regional SVG map takes a full page in the PDF.
4778
+ When the Scene has pins, its Adventure bundle carries the Scene and the JournalEntry generated from its Markdown. Importing that bundle preserves the IDs the pins address. The maps naming one `data.place` share one Adventure.
4158
4779
 
4159
- #### Theatre-of-the-mind maps
4780
+ #### A map in the book
4160
4781
 
4161
- A `totm` map names its background with `data.bgImage` and its canvas size with
4162
- `sohl.dimensions: [width, height]`. It builds a gridless Scene with token vision
4163
- off. It needs no `sohl.pxPerGrid` or `data.scale`. The Markdown body remains the
4164
- map's prose.
4782
+ A PDF book that selects a map note prints each of its Scene's level backgrounds
4783
+ on a landscape page after the entry, titled with the map's name and the level's
4784
+ name. The picture is the level's `background.src` with `data.fixup` applied, so
4785
+ a level whose background is fixed up to a local asset prints that asset. A
4786
+ level with no background prints nothing.
4165
4787
 
4166
4788
  ### type: place
4167
4789
 
@@ -4175,33 +4797,42 @@ map's prose.
4175
4797
  - feature: A place significant by its terrain — forests, rivers, falls, passes, fords.
4176
4798
  - celestial: A body observed from a world rather than located on one — a sun, a planet, a comet.
4177
4799
 
4178
- | `data` property | Values | Description |
4179
- | --------------------------------- | --------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
4180
- | `calendar` | `Address` | Calendar note used to print this place's dates |
4181
- | `demonym` | `string` | What a person from this place is called — a Vylarian |
4182
- | `purpose` | `placeCharacter` tag | The reason a settlement, site, or structure exists |
4183
- | `lore` | `Address[]` | Lore concerning this place — its peoples, its law, its calendar, its history |
4184
- | `parents` | `Address[]` | Enclosing places within which this place is located |
4185
- | `population` | `number` | Approximate population (precision 2 significant digits) |
4186
- | `government` | `Address` or `null` (default type: `affiliation`) | Governing affiliation; explicit null means complete anarchy. Omission warns only for positive population. |
4187
- | `market` | `number` | Market class, 1 to 6 — what trade a settlement supports |
4188
- | `borders` | `{ to, bearing }[]` | Places sharing a frontier with this one, and where each lies from here |
4189
- | `routes` | `{ to, bearing, mode, days, terrain?, leagues? }[]` | Journeys from this place's centre to another place |
4190
- | `world.equatorialCircumferenceKm` | `number` | The distance round the body at its equator, in kilometres |
4191
- | `world.surfaceGravityG` | `number` | Surface gravity, as a multiple of Earth's |
4192
- | `world.axialTiltDegrees` | `number` | The tilt of the axis, in degrees |
4193
- | `year.days` | `number` | How many days the body's year holds |
4194
- | `year.hoursPerDay` | `number` | How many hours the day divides into |
4195
- | `year.minutesPerHour` | `number` | How many minutes the hour divides into |
4196
- | `year.secondsPerMinute` | `number` | How many seconds the minute divides into |
4197
- | `present` | `date` | The day the setting stops and play begins |
4198
- | `body.diameterKm` | `number` | The body's diameter, in kilometres |
4199
- | `body.orbitalRadiusKm` | `number` | How far it orbits from the body it circles, in kilometres |
4200
- | `body.orbit` | `string` | The orbit's shape — `circular` means the cycle never varies |
4201
- | `body.inclined` | `boolean` | Whether the orbit is inclined to the plane the world orbits in |
4202
- | `moon.cycle` | `number` | How many days it takes to return to the same phase |
4203
- | `moon.newOn` | day-precision `date` | A day it was new, written in the reference calendar |
4204
- | `moon.eclipses` | `string` | `never`, `rare`, `occasional` or `frequent` |
4800
+ | `data` property | Values | Description |
4801
+ | --------------------------------- | -------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
4802
+ | `events` | event entries — see [Events](#events) | What happened to or at this subject: dated, attributed events |
4803
+ | `calendar` | `Address` | Calendar note used to print this place's dates |
4804
+ | `demonym` | `string` | What a person from this place is called — a Vylarian |
4805
+ | `purpose` | `placeCharacter` tag | The reason a settlement, site, or structure exists |
4806
+ | `lore` | `Address[]` | Lore concerning this place — its peoples, its law, its calendar, its history |
4807
+ | `parents` | `Address[]` | Enclosing places within which this place is located |
4808
+ | `population` | `number` | Approximate population (precision 2 significant digits) |
4809
+ | `government` | `Address` or `null` (default type: `affiliation`) | Governing affiliation; explicit null means complete anarchy. Omission warns only for positive population. |
4810
+ | `market` | `number` | Market class, 1 to 6 — what trade a settlement supports |
4811
+ | `borders` | `{ to, bearing }[]` | Places sharing a frontier with this one, and where each lies from here |
4812
+ | `borders[].to` | `Address`, required | The other place; the type defaults to `place` |
4813
+ | `borders[].bearing` | `N`, `NE`, `E`, `SE`, `S`, `SW`, `W` or `NW`, required | Where the other place lies from here |
4814
+ | `routes` | `{ to, bearing, mode, days, terrain?, leagues? }[]` | Journeys from this place's centre to another place |
4815
+ | `routes[].to` | `Address`, required | The other place; the type defaults to `place` |
4816
+ | `routes[].bearing` | `N`, `NE`, `E`, `SE`, `S`, `SW`, `W` or `NW`, required | Where the destination lies from here |
4817
+ | `routes[].mode` | `land`, `boat` or `ship`, required | How the journey is travelled |
4818
+ | `routes[].days` | `1`, `2`, `3`, `5`, `10`, `20`, `30`, `45`, `60`, `90`, `180` or `360`, required | About how many days the journey takes, under normal conditions |
4819
+ | `routes[].terrain` | terrain names, in travel order | The terrains crossed, each crossable by the mode |
4820
+ | `routes[].leagues` | `number` | The distance, in leagues |
4821
+ | `world.equatorialCircumferenceKm` | `number` | The distance round the body at its equator, in kilometres |
4822
+ | `world.surfaceGravityG` | `number` | Surface gravity, as a multiple of Earth's |
4823
+ | `world.axialTiltDegrees` | `number` | The tilt of the axis, in degrees |
4824
+ | `year.days` | `number` | How many days the body's year holds |
4825
+ | `year.hoursPerDay` | `number` | How many hours the day divides into |
4826
+ | `year.minutesPerHour` | `number` | How many minutes the hour divides into |
4827
+ | `year.secondsPerMinute` | `number` | How many seconds the minute divides into |
4828
+ | `present` | `date` | The day the setting stops and play begins |
4829
+ | `body.diameterKm` | `number` | The body's diameter, in kilometres |
4830
+ | `body.orbitalRadiusKm` | `number` | How far it orbits from the body it circles, in kilometres |
4831
+ | `body.orbit` | `string` | The orbit's shape — `circular` means the cycle never varies |
4832
+ | `body.inclined` | `boolean` | Whether the orbit is inclined to the plane the world orbits in |
4833
+ | `moon.cycle` | `number` | How many days it takes to return to the same phase |
4834
+ | `moon.newOn` | day-precision `date` | A day it was new, written in the reference calendar |
4835
+ | `moon.eclipses` | `string` | `never`, `rare`, `occasional` or `frequent` |
4205
4836
 
4206
4837
  #### Why a place exists
4207
4838
 
@@ -4340,9 +4971,7 @@ a package boundary uses the same terrain and mode rules at both ends.
4340
4971
  For every place that participates in a border or route, the map builder draws
4341
4972
  an itinerary from that place. A site page carries it as a linked SVG. A PDF
4342
4973
  book that includes the place gives its map a separate full page after the
4343
- entry. A configured Foundry Scene pack carries a gridless map backed by a
4344
- generated PNG, with Notes linked to importable place journals. Places with no
4345
- relations create no itinerary output.
4974
+ entry. Places with no relations create no itinerary output.
4346
4975
 
4347
4976
  **A relation that crosses a package boundary is written in full at both ends.**
4348
4977
  An omitted `<package>` segment is the package being built, in whatever note the
@@ -4427,7 +5056,7 @@ Write `government: null` for **complete anarchy**. Omitting the key leaves gover
4427
5056
  | Any | Explicit `null` | None; complete anarchy |
4428
5057
  | Any | Affiliation Address | None; the reference must resolve |
4429
5058
 
4430
- 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. Legacy affiliation `data.domains` is accepted temporarily but ignored. Preserve ownership and influence facts in prose; see [government migration](../guides/government-migration.md).
5059
+ 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.
4431
5060
 
4432
5061
  #### Population figures
4433
5062