@heroiclands/package-build 23.12.4 → 23.12.6

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 (55) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/content-config.mjs +26 -0
  3. package/docs/api.md +9 -5
  4. package/docs/authoring/dates-and-calendars.md +29 -1
  5. package/docs/authoring/frontmatter.md +1 -1
  6. package/docs/authoring/links-and-markup.md +7 -7
  7. package/docs/configuration.md +30 -4
  8. package/docs/guides/book.md +12 -12
  9. package/docs/guides/module-project.md +1 -1
  10. package/docs/reference/format-details.md +81 -24
  11. package/docs/reference/note-types.md +10 -11
  12. package/engine/content-format.yaml +0 -2
  13. package/engine/content-index.mjs +23 -41
  14. package/engine/content-links.mjs +3 -0
  15. package/engine/event-fields.mjs +24 -1
  16. package/engine/event-rows.mjs +82 -2
  17. package/engine/event-views.mjs +74 -17
  18. package/engine/frontmatter-lint.mjs +11 -0
  19. package/engine/generated-sections.mjs +8 -1
  20. package/engine/holdings.mjs +8 -2
  21. package/engine/index-records.mjs +1 -0
  22. package/engine/infobox-render.mjs +16 -5
  23. package/engine/infobox.mjs +27 -10
  24. package/engine/literature-works.mjs +8 -2
  25. package/engine/markdown-expressions.mjs +72 -17
  26. package/engine/metadata-index.mjs +3 -0
  27. package/engine/name-sort.mjs +91 -0
  28. package/engine/note-calendars.mjs +314 -0
  29. package/engine/note-frontmatter.mjs +1 -1
  30. package/engine/note-vocabulary.mjs +12 -17
  31. package/engine/page-lists.mjs +3 -2
  32. package/engine/pdf-index.mjs +11 -4
  33. package/engine/pdf-pages.mjs +2 -1
  34. package/engine/pdf-render.mjs +43 -13
  35. package/engine/pdf-toc.mjs +4 -3
  36. package/engine/reckoning-markers.mjs +63 -3
  37. package/engine/related-pages.mjs +12 -2
  38. package/engine/site-build.mjs +3 -0
  39. package/engine/sql-tables.mjs +28 -7
  40. package/package.json +1 -1
  41. package/types/content-config.d.mts +12 -0
  42. package/types/engine/content-index.d.mts +9 -32
  43. package/types/engine/event-fields.d.mts +11 -0
  44. package/types/engine/event-rows.d.mts +19 -1
  45. package/types/engine/event-views.d.mts +8 -3
  46. package/types/engine/generated-sections.d.mts +6 -0
  47. package/types/engine/holdings.d.mts +7 -1
  48. package/types/engine/infobox.d.mts +11 -0
  49. package/types/engine/literature-works.d.mts +5 -0
  50. package/types/engine/name-sort.d.mts +49 -0
  51. package/types/engine/note-calendars.d.mts +60 -0
  52. package/types/engine/pdf-render.d.mts +8 -0
  53. package/types/engine/pdf-toc.d.mts +1 -1
  54. package/types/engine/reckoning-markers.d.mts +32 -1
  55. package/types/engine/related-pages.d.mts +5 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @heroiclands/package-build
2
2
 
3
+ ## 23.12.6
4
+
5
+ ### Patch Changes
6
+
7
+ A package can name a default calendar with `defaultCalendar` in its configuration, and it replaces the world note's calendar as the one dates fall back to.
8
+
9
+ A note's dates print in its own `data.calendar`, which any note may now set, else its culture's, else for a place its parents', else the default. A place whose parents keep different calendars is a build error until it names its own.
10
+
11
+ Chronologies and the other event sections print every date in the calendar of the page showing them, and `dateformat` with no calendar named uses the note's.
12
+
13
+ ## 23.12.5
14
+
15
+ ### Patch Changes
16
+
17
+ In PDF books, the page number and section name at the foot of each page are set at the size of the body text.
18
+
19
+ In PDF books, list items sit apart from one another and carry a bullet large enough to see at book size.
20
+
21
+ In PDF books, a reference to another book that already sits in brackets joins them, reading (The Crossing, Thal. p524) rather than nesting a second pair.
22
+
23
+ Chronology sections, and the other event sections, list each event's date first, written in the setting's calendar. A chronology shows its Felt here column only when some event is felt in the place, and prints across the full page in PDF books. A captioned table can ask to span the page in a PDF book with `.full-width`. A wide table floats to where it fits, and the text runs on past its heading rather than leaving an empty page.
24
+
25
+ In PDF books, a profile box too long for the rest of a page continues on the next one between its rows, instead of running off the page over the footer.
26
+
27
+ A note's name may give a `sort` form, the way an index would write it: `sort: Black Flame, The` for _The Black Flame_, or `sort: Hilvan, Doran`. It files the note in the book index, page lists and other name-ordered lists, and it is the note's entry text in the book index; every other list still shows the full name. Authored `sql` fences can order by the new `nameSort` column of `entries`, which is the `sort` form or, without one, the full name.
28
+
29
+ Profile figures read as numbers do: 12,500 under a million, and 11 million or 1.2 million above it, on the website, in Foundry and in PDF books.
30
+
3
31
  ## 23.12.4
4
32
 
5
33
  ### Patch Changes
@@ -571,6 +571,10 @@ export function publishesContentPages(config) {
571
571
  * resolved against it, so the build never
572
572
  * depends on the working directory.
573
573
  * @property {string} [currentDate] Setting-wide neutral current date; defaults to "720.1".
574
+ * @property {string} [defaultCalendar] Shortcode of the `lore` note with
575
+ * `subType: calendar` that prints the
576
+ * dates of a note no other rule gives a
577
+ * calendar.
574
578
  * @property {string} contentPackage Content package name — the address
575
579
  * namespace every note in this
576
580
  * repository is published under.
@@ -646,6 +650,8 @@ export function publishesContentPages(config) {
646
650
  *
647
651
  * @typedef {object} ContentBuildConfig
648
652
  * @property {string} currentDate Setting-wide neutral current date.
653
+ * @property {string|null} defaultCalendar The calendar of last resort's
654
+ * shortcode, `null` when none is named.
649
655
  * @property {string} rootDir
650
656
  * @property {string} contentPackage
651
657
  * @property {string|null} foundryPackage `null` for a `documentation`
@@ -730,6 +736,7 @@ const CONFIG_KEYS = [
730
736
  "rootDir",
731
737
  "contentPackage",
732
738
  "currentDate",
739
+ "defaultCalendar",
733
740
  "foundryPackage",
734
741
  "homepage",
735
742
  "authors",
@@ -912,6 +919,24 @@ function fail(field, problem) {
912
919
  throw Object.assign(new TypeError(`package-build config: \`${field}\` ${problem}.`), { field });
913
920
  }
914
921
 
922
+ /**
923
+ * The configured `defaultCalendar`: a calendar note's shortcode, or `null`.
924
+ * Whether it names a calendar note is checked against the content tree when
925
+ * the content index is built.
926
+ *
927
+ * @param {unknown} value - The configured value.
928
+ * @returns {string|null} The shortcode.
929
+ */
930
+ function normalizeDefaultCalendar(value) {
931
+ if (value === undefined || value === null) return null;
932
+ if (typeof value !== "string" || !isAddressSegment(value))
933
+ fail(
934
+ "defaultCalendar",
935
+ "must be the shortcode of a calendar note — lowercase letters and digits",
936
+ );
937
+ return /** @type {string} */ (value);
938
+ }
939
+
915
940
  /**
916
941
  * @param {object} object
917
942
  * @param {readonly string[]} allowed
@@ -2973,6 +2998,7 @@ export function defineConfig(config) {
2973
2998
  fail("currentDate", error.message);
2974
2999
  }
2975
3000
  })(),
3001
+ defaultCalendar: normalizeDefaultCalendar(input.defaultCalendar),
2976
3002
  contentPackage: requireContentPackage(input.contentPackage, docEntryTypes, {
2977
3003
  rootDir,
2978
3004
  packageKind,
package/docs/api.md CHANGED
@@ -384,6 +384,7 @@ The declared infobox: what a note's summary panel holds, decided once and render
384
384
  | `assertInfoboxSet` | `assertInfoboxSet(boxes, fm, options)` | `readonly object[]`, throws | refusing a page that carries anything but the boxes its type maps to |
385
385
  | `buildInfoboxes` | `buildInfoboxes(fm, options)` | `object[]` | building every box a note carries, against a given set of maps and declarations |
386
386
  | `defineInfobox` | `defineInfobox(declaration)` | `object` | declaring one system's half of the infobox |
387
+ | `formatQuantity` | `formatQuantity(value)` | `string` | writing a number as a profile shows it: `12,500` under a million, `11 million` above |
387
388
  | `hasRenderableValue` | `hasRenderableValue(kind, value)` | `boolean` | deciding whether a built value is worth a row |
388
389
  | `hasValue` | `hasValue(value)` | `boolean` | deciding whether an authored value is worth a row |
389
390
  | `humanizeFieldName` | `humanizeFieldName(name)` | `string` | turning a declared key into the label a reader sees |
@@ -722,7 +723,7 @@ resolved value: the culture a place or affiliation inherits through
722
723
 
723
724
  ### `engine.markdownExpressions`
724
725
 
725
- `renderMarkdownExpressions(body, { fm, dates, sqlResults, figures, file, bodyLine })` expands scalar frontmatter references and registered Handlebars helpers outside Markdown code. The `dateformat` helper uses `formatDateInCalendar`; `gt`, `gte`, `lt`, `lte`, `eq`, `and`, `or`, and `not` evaluate explicit comparisons. The `sql` helper reads a prepared scalar result, which must contain one row and one column. The `ref` helper links to a captioned item by its anchor — `"#thorn"` on the same note — in `number` (the default, and admitted explicitly), `full` or `title` form; `figures` is a `Map` of this note's own figures, by id, to `{label, caption, hasCaption}`, and an address naming another note is reported as unresolved rather than looked up. `sqlQueriesInMarkdown` discovers SQL calls, including nested calls; `prepareInlineSqlExpressions` evaluates them through the same DuckDB connection as SQL tables. `EXPRESSION_HELPERS` is the one list of helpers: the engine registers from it and the authoring document is checked against it, so each name there carries the parameters it takes and a sentence on what it does. The renderer returns `{ markdown, findings }`, with source positions for invalid expressions. Site, Foundry and PDF passes invoke it after generated tables expand and before links resolve. Hugo shortcodes remain literal for the site renderer.
726
+ `renderMarkdownExpressions(body, { fm, dates, sqlResults, figures, file, bodyLine })` expands scalar frontmatter references and registered Handlebars helpers outside Markdown code. The `dateformat` helper uses `formatDateInCalendar`, in the calendar it names or else the note's resolved calendar, which it reads from `dates.noteCalendars` — the map a reckoning context built over content-index records carries; `gt`, `gte`, `lt`, `lte`, `eq`, `and`, `or`, and `not` evaluate explicit comparisons. The `sql` helper reads a prepared scalar result, which must contain one row and one column. The `ref` helper links to a captioned item by its anchor — `"#thorn"` on the same note — in `number` (the default, and admitted explicitly), `full` or `title` form; `figures` is a `Map` of this note's own figures, by id, to `{label, caption, hasCaption}`, and an address naming another note is reported as unresolved rather than looked up. `sqlQueriesInMarkdown` discovers SQL calls, including nested calls; `prepareInlineSqlExpressions` evaluates them through the same DuckDB connection as SQL tables. `EXPRESSION_HELPERS` is the one list of helpers: the engine registers from it and the authoring document is checked against it, so each name there carries the parameters it takes and a sentence on what it does. The renderer returns `{ markdown, findings }`, with source positions for invalid expressions. Site, Foundry and PDF passes invoke it after generated tables expand and before links resolve. Hugo shortcodes remain literal for the site renderer.
726
727
 
727
728
  | Export | Signature | Returns | Use it when |
728
729
  | --------------------------- | ------------------------------------------ | ---------------------- | ------------------------------------------------ |
@@ -735,10 +736,13 @@ resolved value: the culture a place or affiliation inherits through
735
736
 
736
737
  The corpus registry anchors each calendar's year 1, day 1 to its canonical `data.epoch` and maps every declared era to that calendar. Exactly one `start: null` era covers earlier years and counts backwards; exactly one `start: 1` era begins the forward count. Other starts are distinct positive calendar years. Numeric order determines bounds, irrespective of array order. Duplicate starts and markers, missing required eras, and invalid epochs are findings. Short qualifiers are ambiguous when they name eras in several packages; a full Address selects one.
737
738
 
738
- | Export | Signature | Returns | Use it when |
739
- | ------------------------- | --------------------------------------------- | ---------------------------------------- | ----------------------------------------------------------- |
740
- | `resolveReckoningMarkers` | `resolveReckoningMarkers(index, daysPerYear)` | `{eras, markers, findings}` | resolving authored eras, their markers, and their bounds |
741
- | `reckoningContext` | `reckoningContext(index)` | `{eras, markers, daysPerYear, findings}` | sharing one resolved date context across checks on a corpus |
739
+ | Export | Signature | Returns | Use it when |
740
+ | ------------------------- | --------------------------------------------- | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
741
+ | `resolveReckoningMarkers` | `resolveReckoningMarkers(index, daysPerYear)` | `{eras, markers, findings}` | resolving authored eras, their markers, and their bounds |
742
+ | `reckoningContext` | `reckoningContext(index)` | `{eras, markers, daysPerYear, findings, noteCalendars}` | sharing one resolved date context across checks on a corpus |
743
+ | `noteCalendarMap` | `noteCalendarMap(notes)` | `Map<string, string>` | reading each record's `resolvedCalendar` by note, as `reckoningContext` carries it in `noteCalendars` |
744
+ | `noteCalendarKey` | `noteCalendarKey(fm)` | `string \| undefined` | finding a note's entry in `noteCalendars` by its type and shortcode |
745
+ | `calendarAddress` | `calendarAddress(value)` | `string \| undefined` | reading a record's `resolvedCalendar`, tuple or string, as its canonical Address |
742
746
 
743
747
  ### `engine.calendarNotes`
744
748
 
@@ -84,7 +84,35 @@ package-build dateto commoncal 326.114 --format long
84
84
 
85
85
  The CLI `datefrom` command requires a day and reads the default (`std`, or first) pattern. `dateto` prints the era covering the canonical day. A clock time makes a date exact; a year or day without one spans the stated interval. `data.epoch` and `data.moon.newOn` require a day. The [detailed date rules](../reference/format-details.md#dates-and-calendars) describe precision and bounds.
86
86
 
87
- In prose, `{{dateformat "commoncal" data.born}}` prints a date in the chosen calendar. `{{dateformat data.calendar data.born}}` uses the note's calendar Address. A third argument chooses another named pattern. A being or place can set `data.calendar`; its infobox uses that calendar for dates.
87
+ In prose, `{{dateformat "commoncal" data.born}}` prints a date in the chosen calendar, and `{{dateformat data.born}}` prints it in the note's own calendar. A last argument chooses another named pattern: `{{dateformat "commoncal" data.born "long"}}`, or `{{dateformat data.born "long"}}`.
88
+
89
+ ## Choose the calendar a note's dates print in
90
+
91
+ Every note reads its dates in one calendar. The infobox's birth and death dates, `dateformat` with no calendar named, and every date in the event sections the build adds to the note's page all print in it. It is the first of:
92
+
93
+ 1. the note's own `data.calendar`, which any note may set and which always wins;
94
+ 2. its culture's calendar — the `data.calendar` of the culture note its `data.culture` names;
95
+ 3. for a place, its parents' calendar — the calendar each place in its `data.parents` reads in, by these same rules;
96
+ 4. the package's `defaultCalendar`, set in the [configuration](../configuration.md#defaultcalendar);
97
+ 5. otherwise none, and a date prints as it was written.
98
+
99
+ ```yaml
100
+ # package-build.config.yaml
101
+ defaultCalendar: commoncal
102
+ ```
103
+
104
+ ```yaml
105
+ # A town in a province that keeps the Vylarian count
106
+ type: place
107
+ subType: settlement
108
+ shortcode: brenford
109
+ data:
110
+ parents: [vylaria]
111
+ ```
112
+
113
+ Brenford names no calendar and no culture, so it reads in Vylaria's. A place whose parents read in **different** calendars is a build error at its `data.parents`, naming the place and each calendar; give the place its own `data.calendar` to settle it. A parent, or a culture, that only reaches the default counts for nothing, so a place among parents that all fall through to `defaultCalendar` takes the default without an error.
114
+
115
+ An event section prints every date in the calendar of the page showing it, whichever note the event is written on: Brenford's chronology reads in Vylaria's count even where an event comes from a history kept in the common calendar. The [format reference](../reference/format-details.md#a-notes-calendar) gives the rules in full.
88
116
 
89
117
  ## Write a recurring date
90
118
 
@@ -21,7 +21,7 @@ data: {}
21
21
  ---
22
22
  ```
23
23
 
24
- `name` is a map with a required, nonempty `full` display name. Every note may also use `aliases` for an ordered list of other names. The note infobox lists aliases directly beneath the full name. For a `being` with `subType: character`, `given` and `clan` are optional name components. The first alias of a character or NPC is its nickname. Omit optional keys when they do not apply; `given`, `clan`, and alias entries must be nonempty strings when present. No other keys are accepted under `name`.
24
+ `name` is a map with a required, nonempty `full` display name. Every note may also use `aliases` for an ordered list of other names, and `sort` for the form the name takes in an index, such as `Black Flame, The` or `Hilvan, Doran`. The note infobox lists aliases directly beneath the full name. `sort` files the note wherever notes are ordered by name — the book index, page lists, generated lists of related notes, and the `nameSort` column of the `entries` relation — and is the note's entry text in the book index. Every other list still displays the `full` name. A note with no `sort` files and indexes by its `full` name. For `name: {full: The Black Flame, sort: "Black Flame, The"}`, the book index prints _Black Flame, The_ under **B**, and a page list prints _The Black Flame_ at the same place.
25
25
 
26
26
  `description` is the short page summary. `tags` hold draft state and descriptive labels. The note type's classification belongs in `subType` where it is declared. `data` holds facts about the subject shared by systems. A YAML comment is the place for an author-only note: commented values remain valid YAML but do not enter the content index or generated documents.
27
27
 
@@ -197,7 +197,7 @@ The caption attaches to exactly the next supported block:
197
197
 
198
198
  The optional `type` attribute overrides inference and accepts `figure`, `table`, `poetry`, `code`, `prose`, and `example`. `type=example` uses **Example 1**, **Example 2**, and so on. It does not allow an unsupported target. A heading, list, thematic break, another caption or end of document after a caption is an error. Caption markers without separating spaces or caption text are errors too.
199
199
 
200
- Identifiers are optional and must be unique within the note. Classes are unrestricted; `.border` uses the shared border style, while other classes can be styled by the medium. Named attributes use `key=value`, with quoted values for text containing spaces. Use `#id` and `.class` rather than `id=` and `class=`; event-handler attributes are refused.
200
+ Identifiers are optional and must be unique within the note. Classes are unrestricted; `.border` uses the shared border style, while other classes can be styled by the medium. On a captioned table or SQL fence, `.full-width` sets the table across the page in a PDF book instead of in one column (`: Regional trade routes {.full-width}`); the other surfaces ignore it. Named attributes use `key=value`, with quoted values for text containing spaces. Use `#id` and `.class` rather than `id=` and `class=`; event-handler attributes are refused.
201
201
 
202
202
  Each numbered type has its own counter. Websites and Foundry number within a note; books number across their reading order. Unnumbered captions neither display nor consume a number. A map image can retain its asset-derived **Map** classification when no type is specified.
203
203
 
@@ -543,7 +543,7 @@ A column's heading is its SQL alias, so `AS "Name"` is what a reader sees. A cel
543
543
  | `market` | The market scale as three columns — `value`, `name`, `trade` — so a table can print `village` beside the number a note wrote. |
544
544
  | `<package>.notes` | The same relations — `notes`, `entries`, `events`, `names`, `words`, `affixes`, `fields`, `glossary`, `language_lineage`, `dictionary`, `terms`, `register`, `tongues`, `retired`, `scope`, `letters`, `edges`, `clusters`, `stress`, `finals`, `syllables`, `joining`, `joins`, `marks`, `skeleton`, `frames`, `read_past`, `mutations`, `cluster_groups`, `sound_changes`, `elements`, `roots`, `cognates`, `calling_names`, `older`, `negation`, `name_shapes`, `name_edges`, `name_draws`, `held_from` and `near_names` — for each package this one declares a dependency on, in a schema named for it. |
545
545
 
546
- Nested frontmatter is addressed exactly as a note writes it: `name.full`, `sohl.weight`, `data.born`. Every Address is a string — the full canonical Address, as in `list_contains(data.parents, 'thalorna-note-place-xerathia')` — whichever package published it. Every note carries a computed `state` column of `full`, `draft` or `stub`. Notes tagged `gm` are absent from the relations on public surfaces.
546
+ Nested frontmatter is addressed exactly as a note writes it: `name.full`, `sohl.weight`, `data.born`. Every Address is a string — the full canonical Address, as in `list_contains(data.parents, 'thalorna-note-place-xerathia')` — whichever package published it. Every note carries a computed `state` column of `full`, `draft` or `stub`, and a `nameSort` column holding its `name.sort` or, without one, its `name.full`, to `ORDER BY`. Notes tagged `gm` are absent from the relations on public surfaces.
547
547
 
548
548
  ### Sections the build adds
549
549
 
@@ -567,7 +567,7 @@ The vale holds three villages, of which only [[place-ford|Ford]] is walled.
567
567
 
568
568
  ### Sections the build adds about events
569
569
 
570
- A note's events are listed for you on the notes they concern: a place gets a **Chronology** of what happened there and below it, with every `depth: world` event as context, a being, affiliation or people the **Events** it took part in, an affiliation, place or people the **Accounts** it gives, and a note holding events **What followed** them. Each is a section appended after everything you wrote, with a fixed anchor — `chronology`, `events`, `accounts`, `followed` — and it appears only where it has something to list.
570
+ A note's events are listed for you on the notes they concern: a place gets a **Chronology** of what happened there and below it, with every `depth: world` event as context, a being, affiliation or people the **Events** it took part in, an affiliation, place or people the **Accounts** it gives, and a note holding events **What followed** them. Each is a section appended after everything you wrote, with a fixed anchor — `chronology`, `events`, `accounts`, `followed` — and it appears only where it has something to list. Each lists the date first, written in the setting's calendar, followed by what happened; a Chronology adds a **Felt here** column only where some event is felt in the place, and a PDF book prints it across the full page width.
571
571
 
572
572
  To replace one, write the section yourself with the same anchor. The build then adds nothing for it and leaves yours exactly as written:
573
573
 
@@ -577,7 +577,7 @@ To replace one, write the section yourself with the same anchor. The build then
577
577
  The fells keep no reckoning before the raising.
578
578
 
579
579
  ```sql
580
- SELECT summary AS "What happened", "when" AS "When"
580
+ SELECT summary AS "What happened", whenText AS "When"
581
581
  FROM events
582
582
  WHERE list_contains("where".locus, 'thalorna-note-place-ironfells')
583
583
  ORDER BY whenSort
@@ -1342,7 +1342,7 @@ The first call lists every page tagged `key-concept` alphabetically by title. Th
1342
1342
  An expression in `{{ }}` is replaced by a value, inline in a sentence. The note's own frontmatter is the context, so a field is read by the path a note writes it at.
1343
1343
 
1344
1344
  ```markdown
1345
- {{name.full}} was born on {{dateformat data.calendar data.born}}.
1345
+ {{name.full}} was born on {{dateformat data.born}}.
1346
1346
  There are {{words (sql "SELECT COUNT(*) FROM notes WHERE type = 'being'")}} beings.
1347
1347
  ```
1348
1348
 
@@ -1373,14 +1373,14 @@ There are {{words (sql "SELECT COUNT(*) FROM notes WHERE type = 'being'")}} bein
1373
1373
  | `words` | `number` | The number spelled out for running prose — `1200` becomes one thousand two hundred. Whole numbers only; a decimal is a finding, and `digits` takes one. |
1374
1374
  | `digits` | `number` | The number as a grouped numeral — `1200` becomes 1,200, and a fractional part is kept. |
1375
1375
  | `sql` | `"query"` | The single value a query returns, for use inside a sentence. The query is a quoted string, the same SQL a table fence takes. |
1376
- | `dateformat` | `calendar date ["format"]` | A date written in a calendar. The calendar is an Address or its shortcode, the date is the value a note carries, and the optional third argument names an output pattern. |
1376
+ | `dateformat` | `[calendar] date ["format"]` | A date written in a calendar. The calendar is an Address or its shortcode; left out, it is the note's own calendar — its `data.calendar`, else its culture's, else for a place its parents', else the configured `defaultCalendar` — and a note with none prints the date as written. The date is the value a note carries, and the optional last argument names an output pattern. |
1377
1377
  | `ref` | `address [form="number"\|"full"\|"title"] \| address field="when"\|"until"\|"kind"\|"summary"\|"name"` | A link to a captioned item, by its anchor — `"#thorn"` on this note, `"note-address#thorn"` on another. `form` is `number` (the default, and admitted explicitly), rendering "Figure 13"; `full`, the number and the caption; or `title`, the caption alone. Always renders as a link to the figure, and a link inside the caption contributes only its label text. The number rendered is the one the figure carries on the surface doing the rendering, whichever note names it. With `field` in place of `form`, the address names an event — `"place-ironfells#sack"`, `"#sack"` on this note, or `"lore-founding"` for a note holding one event — and the reference prints that event's `when`, `until`, `kind`, `summary` or `name` as plain text, never a link; a date prints as the note format prints any date. |
1378
1378
 
1379
1379
  <!-- expression-helpers:end -->
1380
1380
 
1381
1381
  A helper that is given the wrong kind of value reports it rather than printing something wrong: `words` refuses a decimal, the four comparisons refuse anything that is not a finite number, and `dateformat` refuses a date it cannot resolve in the calendar it was given.
1382
1382
 
1383
- See [date rules](dates-and-calendars.md) for what `dateformat` accepts and the patterns its third argument names.
1383
+ See [date rules](dates-and-calendars.md) for what `dateformat` accepts, the calendar it uses when none is named, and the patterns its last argument names.
1384
1384
 
1385
1385
  ### An event's date, inline
1386
1386
 
@@ -54,7 +54,7 @@ around its own evaluation.
54
54
 
55
55
  ### Quick reference
56
56
 
57
- 24 top-level keys. `rootDir` is not one of them — a data configuration never
57
+ 25 top-level keys. `rootDir` is not one of them — a data configuration never
58
58
  writes it — and is documented under [Derived values](#derived-values) instead,
59
59
  alongside `foundryPackage`, `homepage`, `author` and `itemBuilders`, whose
60
60
  data-configuration behaviour is also derivation rather than ordinary
@@ -63,6 +63,7 @@ authoring.
63
63
  | Key | Type | Required | Default |
64
64
  | ------------------------------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | ------------------------- |
65
65
  | [`currentDate`](#currentdate) | quoted neutral date string | no | `"720.1"` |
66
+ | [`defaultCalendar`](#defaultcalendar) | calendar note shortcode | no | — |
66
67
  | [`contentPackage`](#contentpackage) | string | yes | — |
67
68
  | [`foundryPackage`](#foundrypackage) | string | yes (`.mjs` only — derived in YAML); refused in a `documentation` package | — |
68
69
  | [`homepage`](#homepage) | string | no (`.mjs` only — derived in YAML) | `null` |
@@ -88,7 +89,7 @@ authoring.
88
89
 
89
90
  Any key outside this list is refused:
90
91
 
91
- > `` `<key>` is not a recognized option (expected one of: rootDir, contentPackage, currentDate, foundryPackage, homepage, authors, packageKind, stats, itemBuilders, paths, skipDirectories, forbidGeneratedArt, icons, packs, docs, site, pdf, compatibility, relationships, systems, requiresSystem, packageBuild, publish, changelog). ``
92
+ > `` `<key>` is not a recognized option (expected one of: rootDir, contentPackage, currentDate, defaultCalendar, foundryPackage, homepage, authors, packageKind, stats, itemBuilders, paths, skipDirectories, forbidGeneratedArt, icons, packs, docs, site, pdf, compatibility, relationships, systems, requiresSystem, packageBuild, publish, changelog). ``
92
93
 
93
94
  (`rootDir` appears in that list because it is a key `defineConfig` itself
94
95
  accepts — an `.mjs` configuration authors it directly. A YAML configuration
@@ -195,7 +196,7 @@ build writes its `name` as `params.author`. `null` when `authors` is empty.
195
196
  as an unknown key, at the key's own line, because `authors` is the one list a
196
197
  package names its people in:
197
198
 
198
- > ``package-build config: `author` is not a recognized option (expected one of: rootDir, contentPackage, currentDate, foundryPackage, homepage, authors, packageKind, stats, itemBuilders, paths, skipDirectories, forbidGeneratedArt, icons, packs, docs, site, pdf, compatibility, relationships, systems, requiresSystem, packageBuild, publish, changelog).``
199
+ > ``package-build config: `author` is not a recognized option (expected one of: rootDir, contentPackage, currentDate, defaultCalendar, foundryPackage, homepage, authors, packageKind, stats, itemBuilders, paths, skipDirectories, forbidGeneratedArt, icons, packs, docs, site, pdf, compatibility, relationships, systems, requiresSystem, packageBuild, publish, changelog).``
199
200
 
200
201
  `package.json`'s own `author` is npm's and is not read.
201
202
 
@@ -313,6 +314,29 @@ day. Named calendars, `unknown`, numeric YAML values and malformed dates are
313
314
  configuration errors located at `currentDate`. Birth dates can still use named
314
315
  calendars when the output has the relevant calendar context.
315
316
 
317
+ ### `defaultCalendar`
318
+
319
+ **Type:** string · optional · no default.
320
+
321
+ The shortcode of the `lore` note with `subType: calendar` that prints the dates
322
+ of every note no other rule gives a calendar. A note reads its dates in its own
323
+ `data.calendar`, else its culture's, else — for a place — its parents', and
324
+ only then in this one; with no `defaultCalendar` and nothing else to go on, a
325
+ date prints as it was written. The
326
+ [format reference](reference/format-details.md#a-notes-calendar) gives the
327
+ rules in full.
328
+
329
+ ```yaml
330
+ contentPackage: thalorna
331
+ defaultCalendar: commoncal
332
+ ```
333
+
334
+ A value that is not a lowercase alphanumeric shortcode is a configuration
335
+ error at load. A shortcode that names no calendar note in the package is a
336
+ build error located at `defaultCalendar`:
337
+
338
+ > `defaultCalendar commonkal names no calendar note in thalorna; name the shortcode of a lore note with subType: calendar`
339
+
316
340
  ### `contentPackage`
317
341
 
318
342
  **Type:** string · **Required** · no default.
@@ -1259,7 +1283,9 @@ Each entry of `pdf.books` is one PDF:
1259
1283
  abbreviation and the page, and the other book's index, when
1260
1284
  `pdf.indexSeeAlso` is on, lists the note as `Name: Aelw. p307`. A book
1261
1285
  with no abbreviation is named by its full title in italics, `Name (_Book
1262
- title_, p. 307)`. Each abbreviation is used once, since a reader could not
1286
+ title_, p. 307)`. A link the text closes a bracket on takes the reference
1287
+ inside that bracket after a comma, so `(see The Crossing)` prints
1288
+ `(see The Crossing, Thal. p524)` rather than nesting brackets. Each abbreviation is used once, since a reader could not
1263
1289
  tell which book to open from one shared by two.
1264
1290
  - `contents` is the tree written inline — the same `sectionName` /
1265
1291
  `contents` / `filter` / `file` shape a tree file holds under its own
@@ -174,11 +174,11 @@ the Lyrebird Inn (The Tenebrae Volume, p. 214)
174
174
 
175
175
  Which form a wikilink takes depends on where its target is printed:
176
176
 
177
- | The target is | The link prints |
178
- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
179
- | An entry of the same book, including a note the book reprints | An internal destination |
180
- | An entry of another book, and not of this one | `Name (_Book title_, p. N)`, or `Name (Aelw. pN)` with an abbreviation, with no link |
181
- | A note in no book | The web address of the note's page |
177
+ | The target is | The link prints |
178
+ | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
179
+ | An entry of the same book, including a note the book reprints | An internal destination |
180
+ | An entry of another book, and not of this one | `Name (_Book title_, p. N)`, or `Name (Aelw. pN)` with an abbreviation, with no link; inside a bracket the text closes, `(Name, Aelw. pN)` |
181
+ | A note in no book | The web address of the note's page |
182
182
 
183
183
  The page is the page the PDF itself numbers, which is the number printed in the
184
184
  footer and used by the contents and the index, so the printed `p. N` is the
@@ -406,12 +406,12 @@ A book that prints at least one note ends with an **Index** chapter, grouped
406
406
  under letter headings. Nothing configures it: the build derives it from the
407
407
  notes the book prints.
408
408
 
409
- | Term | Source | Shown as |
410
- | ------------------------ | --------------------- | ---------------------------------------------------------------------------------- |
411
- | A note's name | `name.full` | the page of the note's entry in **bold**, then the pages of every authored mention |
412
- | A name without its head | `name.full` | the same pages as the note's entry, filed as `Targud, Kingdom of` |
413
- | An alias | `name.aliases` | _see_ the note's name |
414
- | An event's in-world name | `data.events[].names` | _see_ the name of the note that holds the event |
409
+ | Term | Source | Shown as |
410
+ | ------------------------ | ----------------------------- | ---------------------------------------------------------------------------------- |
411
+ | A note's name | `name.sort`, else `name.full` | the page of the note's entry in **bold**, then the pages of every authored mention |
412
+ | A name without its head | `name.full` | the same pages as the note's entry, filed as `Targud, Kingdom of` |
413
+ | An alias | `name.aliases` | _see_ the note's name |
414
+ | An event's in-world name | `data.events[].names` | _see_ the name of the note that holds the event |
415
415
 
416
416
  A name that opens with a generic word a reader would not look under, such as
417
417
  `Kingdom of Targud` or `Ritual: Blessing`, is also filed under the rest of the
@@ -460,7 +460,7 @@ Two kinds of link add nothing:
460
460
 
461
461
  Terms sort on the ASCII fold the content index derives for names (`nameAscii`),
462
462
  ignoring case, so an accented name files under its base letter and the order
463
- matches the table of contents. A term that does not begin with a letter files
463
+ matches the table of contents. A note's own entry reads as its `name.sort` when it declares one, in index form such as `Black Flame, The` or `Hilvan, Doran`, and as its `name.full` otherwise; it files, and takes its letter heading, from that form. A note that declares a `sort` is not also filed under `pdf.indexHeads`. A term that does not begin with a letter files
464
464
  first, under `#`. An alias or event name that folds to the same text as the
465
465
  note's own name is not listed again.
466
466
 
@@ -275,7 +275,7 @@ Five keys, and each answers a question the build cannot answer for itself:
275
275
  Everything omitted has a default, and the defaults are the conventional
276
276
  HeroicLands layout: the content tree at `assets/content`, the compiled packs at
277
277
  `build/stage/packs`, the intermediates and caches elsewhere under `build/`.
278
- [`configuration.md`](../configuration.md) documents all eighteen top-level keys,
278
+ [`configuration.md`](../configuration.md) documents every top-level key,
279
279
  what each refusal message means, and the five values that are derived rather
280
280
  than authored.
281
281
 
@@ -379,7 +379,13 @@ content, comment out its YAML lines with `#`. Comments remain valid YAML text
379
379
  and do not become data in the JSONL index, generated pages, or Foundry documents.
380
380
 
381
381
  `name` is a map with a required nonempty `full` string when present. It may
382
- also contain `aliases`, an ordered list of nonempty strings. A being with
382
+ also contain `aliases`, an ordered list of nonempty strings, and `sort`, a nonempty
383
+ string giving the form the name takes in an index, such as `Black Flame, The` or
384
+ `Hilvan, Doran`. `sort` files the note wherever notes are ordered by name (page
385
+ lists, generated lists of related notes, the book index, the `nameSort` column)
386
+ and is the note's entry text in the book index; every other list still displays
387
+ `full`. Without `sort`, the note files and indexes by `full`. Ordering compares
388
+ the ASCII fold of the key (`Árdavon` files beside `Ardavon`). A being with
383
389
  `subType: character` may additionally contain nonempty `given` and `clan`
384
390
  strings. Other keys under `name` are errors. For a character or NPC, the first
385
391
  alias is its nickname. A being's homes belong in `data.homes`.
@@ -426,17 +432,55 @@ A named date uses `datefrom <calendar> <date>`, where the final text follows the
426
432
 
427
433
  `package-build datefrom <calendar> <date>` reads the default calendar pattern and prints a canonical day. `package-build dateto <calendar> <canonical-date>` prints the day in the covering era; `--format <name>` chooses another named output pattern. The [authoring guide](../authoring/dates-and-calendars.md) gives a complete example.
428
434
 
435
+ ##### A note's calendar
436
+
437
+ A note's dates print in one calendar, the first of:
438
+
439
+ 1. its own `data.calendar`, which every note type accepts, and which always
440
+ wins;
441
+ 2. its culture's calendar: the culture note its `data.culture` names, resolved
442
+ by these same rules — in effect that culture's own `data.calendar`;
443
+ 3. for a `place`, its parents' calendar: each note its `data.parents` names,
444
+ resolved by these same rules;
445
+ 4. the package's [`defaultCalendar`](../configuration.md#defaultcalendar);
446
+ 5. otherwise none, and a date prints as it was written.
447
+
448
+ Steps 2 and 3 take only a calendar that some note states. A culture or a
449
+ parent that itself falls through to `defaultCalendar` contributes nothing, so a
450
+ place whose parents all fall through takes the default. Parents that resolve to
451
+ **two or more distinct calendars** are a build error at the place's
452
+ `data.parents`, naming the place and each calendar with the parent it came
453
+ through:
454
+
455
+ ```text
456
+ Places/Edge.md:6:3: error: place edge: data.parents resolve to different calendars (thalorna-note-lore-commoncal via north, thalorna-note-lore-vrcal via south); state data.calendar
457
+ ```
458
+
459
+ Stating `data.calendar` on the place settles it. A cycle through
460
+ `data.parents` or `data.culture` contributes nothing, and the chain goes on to
461
+ `defaultCalendar`. A culture or parent in another package contributes the
462
+ `data.calendar` its published entry states, and nothing else.
463
+
464
+ The calendar decides what a reader sees wherever the note prints a date: the
465
+ infobox's `born` and `died`, `dateformat` with no calendar named, the `events`
466
+ relation's `whenText`, and every date in the [event views](#event-views) the
467
+ note's page shows.
468
+
429
469
  Markdown prose accepts inline `{{...}}` expressions. A property path reads
430
470
  the note's frontmatter, and `dateformat` converts a date to the reckoning used by a
431
- specified calendar. The first argument names a calendar note by shortcode or
432
- Address, or one of its eras by `<calendar>.<era>`. Use a full Address when a
433
- short name is ambiguous. The second argument is a canonical date or a
434
- frontmatter property holding a date. An optional third argument names an output
435
- format from the calendar note. An explicit era that does not cover the date is an error.
471
+ calendar. The first argument names a calendar note by shortcode or Address, or
472
+ one of its eras by `<calendar>.<era>`; left out, the calendar is
473
+ [the note's own](#a-notes-calendar), and a note with none prints the date as
474
+ written. Use a full Address when a short name is ambiguous. The date is a
475
+ canonical date or a frontmatter property holding a date. An optional last
476
+ argument names an output format from the calendar note. With two arguments,
477
+ the first is the calendar unless it is a date that names no calendar, so
478
+ `{{dateformat data.born "long"}}` prints the note's date in its own calendar's
479
+ `long` format. An explicit era that does not cover the date is an error.
436
480
 
437
481
  ```markdown
438
482
  {{name.full}} was born on {{dateformat "vrcal" data.born}}.
439
- {{dateformat data.calendar data.born}}
483
+ {{dateformat data.born}}
440
484
  The event fell on {{dateformat "vrcal" "300.25"}}.
441
485
  {{and (gt 3 5) (lt 4 2)}}
442
486
  {{sql "SELECT COUNT(*) FROM notes WHERE type = 'being'"}}
@@ -864,6 +908,7 @@ noticed:
864
908
  | `seeAlso` | list of `{ address, gloss? }` | Deliberate cross-references in reading order, shown on the site, in journals and in books. |
865
909
  | `seeAlso[].address` | a note `Address` | Required; the whole note to read next. |
866
910
  | `seeAlso[].gloss` | `string` | An optional short phrase saying why to follow the reference. |
911
+ | `calendar` | `Address` | The calendar note this note's dates print in — see [a note's calendar](#a-notes-calendar). |
867
912
  | `id` | `string` | A pinned document identity. |
868
913
  | `pack` | `string` | The shared compendium route. |
869
914
  | `packFolder` | `Address` or pack map | The shared compendium folder Address. |
@@ -2916,7 +2961,9 @@ reads `NULL` rather than failing. `data.culture` is the one field that reads as
2916
2961
  a derived value: the note's own culture, or the one it inherits. See
2917
2962
  [Culture in the index](#culture-in-the-index).
2918
2963
 
2919
- **`notes` leaves out stubs; `entries` does not.** Both carry a derived `state`
2964
+ **`notes` leaves out stubs; `entries` does not.** Both carry a derived `nameSort`
2965
+ column — the note's `name.sort` when it declares one, otherwise its `name.full`,
2966
+ unfolded — for `ORDER BY`, and a derived `state`
2920
2967
  column — `stub`, `draft` or `full` — and `notes` is exactly
2921
2968
  `SELECT * FROM entries WHERE state <> 'stub'`. So every table already written
2922
2969
  selects what it always selected, and gains `state` for free; a table that should
@@ -2957,20 +3004,29 @@ query rather than a list kept by hand:
2957
3004
 
2958
3005
  ````markdown
2959
3006
  ```sql
2960
- SELECT note AS _ref, "when" AS "When", summary AS "What happened"
3007
+ SELECT note AS _ref, whenText AS "When", summary AS "What happened"
2961
3008
  FROM events
2962
3009
  WHERE kind IN ('war', 'siege', 'battle')
2963
3010
  ORDER BY whenSort
2964
3011
  ```
2965
3012
  ````
2966
3013
 
2967
- | Column | What it holds |
2968
- | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2969
- | `note` | The canonical Address of the note the event is written on. |
2970
- | `address` | The event's own Address: `note#id` where the event has an `id`, the note's Address alone where it has none. |
2971
- | `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`. |
2972
- | `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. |
2973
- | `whenYear`, `untilYear` | The canonical year alone, for a filter such as `whenYear BETWEEN 200 AND 299`. |
3014
+ | Column | What it holds |
3015
+ | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
3016
+ | `note` | The canonical Address of the note the event is written on. |
3017
+ | `address` | The event's own Address: `note#id` where the event has an `id`, the note's Address alone where it has none. |
3018
+ | `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`. |
3019
+ | `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. |
3020
+ | `whenText`, `untilText` | The date as a reader of the owning note sees it, printed as `dateformat` prints it in [the owning note's calendar](#a-notes-calendar), else in the era the date itself names; `~` marks an approximate date. A date that does not resolve keeps the text its note wrote. |
3021
+ | `whenIn`, `untilIn` | The date in every calendar: a struct keyed by each calendar note's canonical Address, holding the date as `dateformat` prints it there. `whenIn['thalorna-note-lore-commoncal']` reads it in that calendar; a date that calendar cannot print reads as in `whenText`. |
3022
+ | `whenYear`, `untilYear` | The canonical year alone, for a filter such as `whenYear BETWEEN 200 AND 299`. |
3023
+
3024
+ A fence chooses which calendar its dates print in. `whenText` prints each
3025
+ row in the calendar of the note that owns the event, so a table gathering the
3026
+ events of notes with different calendars reads in more than one count;
3027
+ `whenIn['<calendar Address>']` prints every row in one. The generated [event
3028
+ views](#event-views) do the second, in the calendar of the page showing the
3029
+ view.
2974
3030
 
2975
3031
  `when` and `until` read as the text the note wrote, `~` included. The sort
2976
3032
  keys and years are positions on the canonical axis, which counts a year `0`
@@ -3498,7 +3554,7 @@ The caption attaches to exactly the next supported block:
3498
3554
 
3499
3555
  The optional `type` attribute overrides inference and accepts `figure`, `table`, `poetry`, `code`, `prose`, and `example`. `type=example` uses **Example 1**, **Example 2**, and so on. It does not allow an unsupported target. A heading, list, thematic break, another caption or end of document after a caption is an error. Caption markers without separating spaces or caption text are errors too.
3500
3556
 
3501
- Identifiers are optional and must be unique within the note. Classes are unrestricted; `.border` uses the shared border style, while other classes can be styled by the medium. Named attributes use `key=value`, with quoted values for text containing spaces. Use `#id` and `.class` rather than `id=` and `class=`; event-handler attributes are refused.
3557
+ Identifiers are optional and must be unique within the note. Classes are unrestricted; `.border` uses the shared border style, while other classes can be styled by the medium. On a captioned table or SQL fence, `.full-width` sets the table across the page in a PDF book instead of in one column (`: Regional trade routes {.full-width}`); the other surfaces ignore it. Named attributes use `key=value`, with quoted values for text containing spaces. Use `#id` and `.class` rather than `id=` and `class=`; event-handler attributes are refused.
3502
3558
 
3503
3559
  Each numbered type has its own counter. Websites and Foundry number within a note; books number across their reading order. Unnumbered captions neither display nor consume a number. A map image can retain its asset-derived **Map** classification when no type is specified.
3504
3560
 
@@ -3763,11 +3819,14 @@ The build appends sections to the end of a note's body that list the events conc
3763
3819
 
3764
3820
  | View | Anchor | On | Rows | Columns |
3765
3821
  | ------------- | ------------ | ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- |
3766
- | 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 |
3767
- | 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 |
3768
- | 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 |
3769
- | What followed | `followed` | a note holding events | events whose `follows[].event` names one of this note's events, with how | What followed, When, How |
3770
-
3822
+ | 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 | When, What happened, Felt here |
3823
+ | Events | `events` | a `being`, an `affiliation`, a `lore` note of `subType: culture` | events whose `who[].ref` names the note, with the role it played | When, What happened, Role |
3824
+ | Accounts | `accounts` | an `affiliation`, a `place`, a `lore` note of `subType: culture` | each `accounts[]` entry the note gives, with the event it concerns | When, Event, What they say, Agrees |
3825
+ | What followed | `followed` | a note holding events | events whose `follows[].event` names one of this note's events, with how | When, What followed, How |
3826
+
3827
+ - **Every view's first column is When**, every row's date written in [the calendar of the page showing the view](#a-notes-calendar), whichever note owns the event, so one table reads in one count. The fence reads `whenIn['<calendar Address>']` for that calendar; on a page with no calendar it reads `whenText`, each date in its owning note's calendar. An event whose date does not resolve shows the text its note wrote.
3828
+ - **A chronology's Felt here column appears only where some row is felt in the place.** A place whose rows are all events that happened there, or world events, has the When and What happened columns alone.
3829
+ - **A chronology is always set across the full page width in a PDF book**, whatever its columns.
3771
3830
  - **The views follow everything the author wrote**, in the order of the [generated sections](#generated-sections).
3772
3831
  - **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.
3773
3832
  - **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.
@@ -4068,7 +4127,6 @@ See [a being's subtype describes the subject](#a-beings-subtype-describes-the-su
4068
4127
  | `gender` | `male \| female \| nonbinary \| none \| other` | Gender of the being — see [a being's look](#a-beings-look) |
4069
4128
  | `species` | `Address` | Being's species (lore) |
4070
4129
  | `born` | `date \| unknown` | When the being was born; absent, it was never born |
4071
- | `calendar` | `Address` | Calendar note that prints the being's dates |
4072
4130
  | `died` | `date \| unknown` | When the being died; absent, it is alive |
4073
4131
  | `age` | `34 \| ~34` | Age in years, stated only to override what `born` says; `~` marks an estimate |
4074
4132
  | `ageYears` | `number` | Written by the compiler beside an `age` estimate — the `~` stripped; a note never authors this |
@@ -6970,7 +7028,6 @@ level with no background prints nothing.
6970
7028
  | `data` property | Values | Description |
6971
7029
  | --------------------------------- | -------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
6972
7030
  | `events` | event entries — see [Events](#events) | What happened to or at this subject: dated, attributed events |
6973
- | `calendar` | `Address` | Calendar note that prints this place's dates |
6974
7031
  | `demonym` | `string` | What a person from this place is called — a Vylarian |
6975
7032
  | `purpose` | `placeCharacter` tag | The reason a settlement, site, or structure exists |
6976
7033
  | `lore` | `Address[]` | Lore concerning this place — its peoples, its law, its calendar, its history |