@heroiclands/package-build 22.21.0 → 22.23.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.
- package/CHANGELOG.md +223 -0
- package/assets/styles/content-base.css +162 -0
- package/bin/content-commands.mjs +77 -17
- package/bin/package-build.mjs +15 -2
- package/ci/content-format-reference.mjs +68 -1
- package/config.mjs +26 -0
- package/content-config.mjs +153 -6
- package/docs/api.md +120 -89
- package/docs/authoring/assets.md +14 -0
- package/docs/authoring/dates-and-calendars.md +41 -3
- package/docs/authoring/frontmatter.md +2 -2
- package/docs/authoring/links-and-markup.md +325 -35
- package/docs/commands.md +12 -10
- package/docs/configuration.md +117 -14
- package/docs/content-format.md +4 -2
- package/docs/guides/book.md +5 -4
- package/docs/guides/reference-pages.md +15 -0
- package/docs/reference/format-details.md +545 -104
- package/docs/reference/note-types.md +30 -13
- package/engine/actor-compiler.mjs +23 -0
- package/engine/anchored-sections.mjs +35 -4
- package/engine/anchors.mjs +26 -30
- package/engine/art-fields.mjs +118 -0
- package/engine/art-slots.mjs +7 -1
- package/engine/asset-index.mjs +160 -10
- package/engine/asset-replacement.mjs +93 -0
- package/engine/asset-types.mjs +240 -0
- package/engine/base-compiler.mjs +139 -22
- package/engine/base-styles.mjs +149 -0
- package/engine/bundles.mjs +13 -2
- package/engine/compendiums.mjs +8 -1
- package/engine/content-blocks.mjs +410 -0
- package/engine/content-embeds.mjs +19 -0
- package/engine/content-figures.mjs +468 -0
- package/engine/content-footnotes.mjs +197 -0
- package/engine/content-format-check.mjs +15 -12
- package/engine/content-format.yaml +1 -1
- package/engine/content-images.mjs +126 -25
- package/engine/content-index.mjs +38 -12
- package/engine/content-links.mjs +14 -6
- package/engine/content-tables.mjs +45 -4
- package/engine/content-tasklists.mjs +189 -0
- package/engine/docs-checks.mjs +4 -4
- package/engine/extension-attributes.mjs +48 -2
- package/engine/field-reference.mjs +31 -10
- package/engine/field-spec.mjs +10 -8
- package/engine/foreign-catalog.mjs +143 -18
- package/engine/frontmatter-lint.mjs +120 -65
- package/engine/frontmatter.mjs +3 -3
- package/engine/heading-attributes.mjs +321 -0
- package/engine/helpers.mjs +109 -41
- package/engine/homepage.mjs +8 -8
- package/engine/index.mjs +3 -0
- package/engine/infobox-registry.mjs +4 -1
- package/engine/infobox-render.mjs +15 -3
- package/engine/infobox.mjs +129 -15
- package/engine/itinerary-scenes.mjs +4 -10
- package/engine/journals.mjs +294 -50
- package/engine/lore-events.mjs +197 -0
- package/engine/macros.mjs +1 -1
- package/engine/markdown-expressions.mjs +434 -59
- package/engine/note-dates.mjs +354 -12
- package/engine/note-frontmatter.mjs +7 -16
- package/engine/note-vocabulary.mjs +183 -42
- package/engine/page-lists.mjs +358 -0
- package/engine/pathnames.mjs +36 -0
- package/engine/pdf-build.mjs +431 -74
- package/engine/pdf-images.mjs +64 -0
- package/engine/pdf-render.mjs +563 -66
- package/engine/rank-ladder.mjs +198 -0
- package/engine/reckoning-markers.mjs +1 -1
- package/engine/retired-fields.mjs +8 -13
- package/engine/scenes.mjs +26 -7
- package/engine/site-build.mjs +166 -23
- package/engine/site-config.mjs +10 -1
- package/engine/site-index.mjs +90 -3
- package/engine/site-preview.mjs +20 -7
- package/engine/social-ties.mjs +52 -14
- package/engine/sql-tables.mjs +66 -9
- package/engine/standings.mjs +89 -6
- package/engine/system-block.mjs +56 -30
- package/engine/web-wikilinks.mjs +48 -1
- package/hm3/actors.mjs +8 -5
- package/manifest.mjs +43 -24
- package/package.json +1 -1
- package/packagebuild-metadata.jsonl +13 -13
- package/sohl/actors.mjs +22 -99
- package/sohl/item-fields.mjs +5 -5
- package/sohl/items.mjs +1 -1
- package/sohl/note-schemas.mjs +11 -21
- package/types/config.d.mts +9 -0
- package/types/content-config.d.mts +48 -1
- package/types/engine/actor-compiler.d.mts +11 -0
- package/types/engine/anchored-sections.d.mts +24 -0
- package/types/engine/anchors.d.mts +9 -4
- package/types/engine/art-fields.d.mts +64 -0
- package/types/engine/asset-index.d.mts +43 -0
- package/types/engine/asset-replacement.d.mts +22 -0
- package/types/engine/asset-types.d.mts +18 -0
- package/types/engine/base-compiler.d.mts +19 -17
- package/types/engine/base-styles.d.mts +93 -0
- package/types/engine/content-blocks.d.mts +87 -0
- package/types/engine/content-embeds.d.mts +16 -0
- package/types/engine/content-figures.d.mts +101 -0
- package/types/engine/content-footnotes.d.mts +80 -0
- package/types/engine/content-format-check.d.mts +8 -6
- package/types/engine/content-images.d.mts +78 -12
- package/types/engine/content-index.d.mts +8 -2
- package/types/engine/content-tables.d.mts +12 -4
- package/types/engine/content-tasklists.d.mts +72 -0
- package/types/engine/extension-attributes.d.mts +22 -1
- package/types/engine/field-reference.d.mts +21 -0
- package/types/engine/field-spec.d.mts +20 -16
- package/types/engine/foreign-catalog.d.mts +39 -0
- package/types/engine/frontmatter.d.mts +1 -1
- package/types/engine/heading-attributes.d.mts +179 -0
- package/types/engine/helpers.d.mts +29 -10
- package/types/engine/homepage.d.mts +7 -7
- package/types/engine/index.d.mts +1 -0
- package/types/engine/infobox-registry.d.mts +4 -1
- package/types/engine/infobox-render.d.mts +6 -1
- package/types/engine/infobox.d.mts +6 -0
- package/types/engine/journals.d.mts +41 -12
- package/types/engine/lore-events.d.mts +14 -0
- package/types/engine/markdown-expressions.d.mts +46 -2
- package/types/engine/note-dates.d.mts +64 -1
- package/types/engine/note-frontmatter.d.mts +1 -4
- package/types/engine/note-vocabulary.d.mts +82 -6
- package/types/engine/page-lists.d.mts +126 -0
- package/types/engine/pathnames.d.mts +26 -0
- package/types/engine/pdf-build.d.mts +28 -6
- package/types/engine/pdf-images.d.mts +52 -0
- package/types/engine/pdf-render.d.mts +84 -2
- package/types/engine/rank-ladder.d.mts +32 -0
- package/types/engine/retired-fields.d.mts +4 -6
- package/types/engine/site-build.d.mts +27 -4
- package/types/engine/site-config.d.mts +9 -0
- package/types/engine/site-index.d.mts +67 -1
- package/types/engine/site-preview.d.mts +1 -1
- package/types/engine/sql-tables.d.mts +31 -7
- package/types/engine/standings.d.mts +21 -3
- package/types/engine/system-block.d.mts +37 -14
- package/types/engine/web-wikilinks.d.mts +3 -1
- package/types/hm3/actors.d.mts +21 -3
- package/types/manifest.d.mts +19 -23
- package/types/sohl/actors.d.mts +6 -7
- package/engine/content-admonitions.mjs +0 -114
- package/engine/content-captions.mjs +0 -181
- package/engine/content-secrets.mjs +0 -112
- package/types/engine/content-admonitions.d.mts +0 -24
- package/types/engine/content-captions.d.mts +0 -45
- package/types/engine/content-secrets.d.mts +0 -17
|
@@ -17,7 +17,11 @@ An Address names content independently of its filename or folder. Its full form
|
|
|
17
17
|
|
|
18
18
|
The part after `|` is the displayed link text or an embed's alternative text. An empty label uses the target's current name in a regular link and marks an embed decorative. A missing pipe is an error. Search may use `name.full` and aliases; authored links use Addresses. The [Address reference](../reference/format-details.md#addresses) explains short forms, package qualification, and ambiguity diagnostics.
|
|
19
19
|
|
|
20
|
-
A link to a note tagged `draft` retains its target and carries a visible draft cue. In a book, the cue reads `(draft)` after the link.
|
|
20
|
+
A link to a note tagged `draft` retains its target and carries a visible draft cue. In a book, the cue reads `(draft)` after the link.
|
|
21
|
+
|
|
22
|
+
**An address that resolves nowhere is an error on all three surfaces**, worded the same way by each. The pack build refuses the note and produces no pack from it. The site build and the book build write what they can and fail the run: a page marks the link for the reader, and a book sets `(unresolved link)` after its label. The book is written so the page carrying the mistake can be found, not because the mistake is tolerated there.
|
|
23
|
+
|
|
24
|
+
An HTML comment is an aside to whoever reads the note next, and no surface shows one — the packs and the website emit it into the HTML, where it stays a comment, and a book leaves it out. Write a `markdownlint` pragma or a note about a quoted passage freely. A comment inside a fence or a code span is an example and is printed as written, and a comment that is never closed is an error.
|
|
21
25
|
|
|
22
26
|
## Journal pages and anchors
|
|
23
27
|
|
|
@@ -33,42 +37,133 @@ The harbor faces west.
|
|
|
33
37
|
Travelers present their papers here. See [[#harbor|the harbor]].
|
|
34
38
|
```
|
|
35
39
|
|
|
36
|
-
|
|
40
|
+
A `:::figure` fence starts a JournalEntryPage too, in Foundry alone — the web and the book keep the fence in the flow of the page around it. A fence holding exactly one picture, captioned with plain text and nothing else, becomes a page of type `image`: the picture is its `src`, the caption is `image.caption`, and the page is named for the figure's own number, such as "Figure 3". A fence carrying no caption still takes the `image` type when it holds one picture, named the same way. Every other fence takes a page of type `text` instead — a grouped fence holding more than one picture, an audio embed, a fence whose caption carries emphasis, an icon, or a link, and a fence that shares its page with trailing prose before the next heading or fence.
|
|
37
41
|
|
|
38
|
-
|
|
42
|
+
The prose introducing a fence and the fence itself land on two different Foundry pages, so a reference such as `{{ref "#trade"}}` written just above a fence sends a Foundry reader to a different page than the one carrying the sentence. Give the introducing prose its own heading, or accept that following the reference leaves the page, before relying on a fence to sit inside a longer page's flow.
|
|
39
43
|
|
|
40
|
-
A
|
|
44
|
+
A heading's braces hold an attribute block, not an anchor alone: `#slug` names the anchor, `.class` adds a CSS class, and `key="value"` writes an attribute. The website and a Foundry journal carry all three onto the heading; a book keeps the anchor and drops the rest, because Typst has no stylesheet to name a class in. Braces holding anything but an attribute block — `# The set {a, b}` — are reported at the heading's line and set as written.
|
|
41
45
|
|
|
42
|
-
|
|
43
|
-
Refer to [[#trade|]] for the market routes.
|
|
46
|
+
Another note can link to `[[lore-harbor#customs-house|Customs House]]`. For Items, `{#description}` selects the JournalEntryPage both systems reference, and accepts a heading at any level. A map note can use an anchored heading for a scene pin; the compiler replaces the pin's exported JournalEntry and page IDs with the built note's IDs and uses the heading text as its label. See [map notes](../reference/format-details.md#type-map) for scene fields.
|
|
44
47
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
### A section players must not read
|
|
49
|
+
|
|
50
|
+
Write `.secret` on the heading that opens the section:
|
|
51
|
+
|
|
52
|
+
```markdown
|
|
53
|
+
# The Cellar {#cellar .secret}
|
|
54
|
+
|
|
55
|
+
The contraband is behind the false wall.
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The section runs from that heading to the next heading that opens a page. In Foundry the page is the GM's alone. On the website and in the book the section sits inside the same expandable spoiler and the same labelled block a `:::secret` block gets. The heading keeps its id, so `[[lore-inn#cellar|the cellar]]` still resolves to it.
|
|
59
|
+
|
|
60
|
+
**On the website this is a spoiler, not access control.** The withheld section is in the published page, so anyone who opens the element or reads the page source reads it. Foundry is the only surface that withholds anything. Write nothing in a `.secret` section that would matter if a player read it on the web.
|
|
61
|
+
|
|
62
|
+
A `:::secret` block inside the section is legal and renders as it does anywhere else. `.secret` on a heading that opens no page — a lower-level heading with no anchor — covers no page, and is reported at its own line: give that heading an anchor, or raise it to the top level.
|
|
63
|
+
|
|
64
|
+
The special Actor anchors `{#appearance}` and `{#dossier}` feed the same authored sections to each system's Actor fields, and take an H1 only — not the lower-level heading a journal page may otherwise start from. The section runs to the next H1, nested headings included. An anchor declared on a lower heading is still found, and is a build error rather than a quietly empty field: move the heading to the top level, or drop the anchor if the section is meant to stay unaddressed prose.
|
|
65
|
+
|
|
66
|
+
## Figures and numbered references
|
|
67
|
+
|
|
68
|
+
A `:::figure` fence numbers whatever it holds and, written with an id, makes it a target `{{ref}}` can point to:
|
|
69
|
+
|
|
70
|
+
````markdown
|
|
71
|
+
:::figure {#trade}
|
|
48
72
|
|
|
49
73
|
```sql
|
|
50
74
|
SELECT name.full AS "Market" FROM notes WHERE type = 'place'
|
|
51
75
|
```
|
|
76
|
+
|
|
77
|
+
///
|
|
78
|
+
Regional trade routes
|
|
79
|
+
:::
|
|
80
|
+
|
|
81
|
+
Refer to {{ref "#trade"}} for the market routes.
|
|
52
82
|
````
|
|
53
83
|
|
|
54
|
-
The
|
|
84
|
+
The fence displays **Table 1: Regional trade routes**, and `{{ref "#trade"}}` displays **Table 1** as a link. **A figure is numbered because it is a fence, not because it carries caption text** — an ordinary table or picture written outside any fence is numbered not at all.
|
|
55
85
|
|
|
56
|
-
|
|
86
|
+
**The construct is `:::figure`**, with an optional `{#id .border}` attribute block, closed by `:::`. Everything between the opening line and the closing `:::` is the captioned thing.
|
|
87
|
+
|
|
88
|
+
**The first `///` at the top level of the fence separates the captioned thing from its caption.** A second `///` at the top level is an error — a figure holds one caption. A `///` written inside a nested code fence is content, not a separator, so a captioned code listing can carry `///` as a comment of its own.
|
|
89
|
+
|
|
90
|
+
**The caption is optional.** A fence with no `///` draws its label alone, with nothing under it. So the counter and the label come from the fence itself, whether or not an author writes a caption.
|
|
91
|
+
|
|
92
|
+
**`{#id}` is optional too.** A fence that declares none is still numbered and drawn; it carries no anchor, so nothing can refer to it. Give a figure an id only when prose needs to point at it.
|
|
93
|
+
|
|
94
|
+
**`.border` draws the figure and its label inside a border.** It is the only class the construct accepts — any other class, such as `.wide`, is an error naming the class. `key="value"` is refused outright: a figure takes an id and classes, nothing else.
|
|
95
|
+
|
|
96
|
+
**The counter is derived from the fence's contents, never authored.** A table is a table; an `sql` fence is a table, because its rendered output is one; any other fence or code block is code; pictures alone, one or several, are a figure; everything else is prose. A fence around prose with `.border` is a numbered, referable boxed aside — the `Prose` counter's whole purpose. The counters are `Code`, `Table`, `Figure`, `Map`, and `Prose`. The website and a Foundry journal number each counter within the note; a book numbers each counter across the book in reading order.
|
|
97
|
+
|
|
98
|
+
**A picture counts as `Map` instead of `Figure` when the asset it draws declares `role: map`** in its provenance — see [the asset provenance reference](../reference/format-details.md). The fence's own markup cannot say so; a picture of a map looks like any other picture, so the fact rides entirely on the asset's own record. A fence grouping several pictures counts as `Map` only when every one of them declares the role; one picture without it keeps the whole fence a `Figure`.
|
|
57
99
|
|
|
58
|
-
|
|
100
|
+
**A reference is written `{{ref "#thorn"}}`**, rendering as a link reading "Figure 13". `form="full"` renders the number and the caption; `form="title"` renders the caption alone; `form="number"` is the default, and may be written explicitly. A link written inside the caption contributes only its label text to a `full` or `title` reference, because the reference is itself a link and an anchor cannot nest inside another.
|
|
59
101
|
|
|
60
|
-
A
|
|
102
|
+
**A reference may name another note's figure**, writing the note's address before the anchor: `{{ref "place-thornford#trade"}}` points at the figure `#trade` in `place-thornford`. It renders the number that figure carries **on the surface doing the rendering** — its own count within `place-thornford` on the website and in a Foundry journal, and its place in the book's reading order in the book, which may differ from the number it carries on its own page. An anchor matching no figure in the addressed note is refused, and so is an address naming no note at all.
|
|
103
|
+
|
|
104
|
+
In a Foundry journal, a reference resolves to the figure's own JournalEntryPage — the `image` page a solitary, plainly captioned picture becomes, or the `text` page any other fence becomes — addressed exactly as an authored `[[#anchor|Text]]` link to the same anchor would be. A reference naming another note's figure is not resolved there: a journal addresses a page by UUID, and has none for a note outside the one compiling.
|
|
105
|
+
|
|
106
|
+
**A figure needs contents and a closing `:::`.** Its id, when one is given, must be unique in the note; its caption, when one is given, is the one `///` section the fence carries.
|
|
107
|
+
|
|
108
|
+
A few worked examples. A captioned picture:
|
|
61
109
|
|
|
62
110
|
```markdown
|
|
63
|
-
:::
|
|
64
|
-
The
|
|
111
|
+
:::figure {#thorn}
|
|
112
|
+
![[being-foobar|The Great Beast]]
|
|
113
|
+
///
|
|
114
|
+
The great beast, as drawn by [[person-havard|Havard]].
|
|
115
|
+
:::
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
This draws **Figure 1**, labelled "Figure 1: The great beast, as drawn by Havard." beneath the picture.
|
|
119
|
+
|
|
120
|
+
A grouped fence holding two pictures as one figure — a plate rather than two separate plates:
|
|
121
|
+
|
|
122
|
+
```markdown
|
|
123
|
+
:::figure {#passes}
|
|
124
|
+
![[image-northpass|Northern approach]]
|
|
125
|
+
![[image-southpass|Southern approach]]
|
|
126
|
+
///
|
|
127
|
+
The two approaches to the pass.
|
|
128
|
+
:::
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Both pictures draw together under one label, **Figure 2**, because the fence is the unit the counter numbers — not the pictures inside it.
|
|
132
|
+
|
|
133
|
+
A fence with no caption:
|
|
134
|
+
|
|
135
|
+
```markdown
|
|
136
|
+
:::figure {#anvil}
|
|
137
|
+
![[icon-anvil|A worn anvil]]
|
|
65
138
|
:::
|
|
66
139
|
```
|
|
67
140
|
|
|
68
|
-
|
|
141
|
+
This draws **Figure 3**, with no caption line beneath it, and still carries the anchor `#anvil`.
|
|
142
|
+
|
|
143
|
+
A reference in running prose:
|
|
144
|
+
|
|
145
|
+
```markdown
|
|
146
|
+
See {{ref "#thorn"}} for the plate, or {{ref "#thorn" form="full"}} for the full description.
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
This displays as "See [Figure 1](#thorn) for the plate, or [Figure 1: The great beast, as drawn by Havard.](#thorn) for the full description," each bracketed phrase a link to the figure.
|
|
150
|
+
|
|
151
|
+
A reference to a figure in another note:
|
|
152
|
+
|
|
153
|
+
```markdown
|
|
154
|
+
The market routes are drawn in {{ref "place-thornford#trade"}}.
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
On the website this links into `place-thornford`'s own page, reading "Table 1" — the number that fence carries there, whatever number it carries in the book or in a note of its own.
|
|
158
|
+
|
|
159
|
+
## Images and protected content
|
|
160
|
+
|
|
161
|
+
An image or icon embed stands on its own line; one that does not is a lint error naming the line, because a width or a position means nothing applied to a word in the middle of a sentence. `size` accepts `auto`, `small`, `medium`, `large`, `xlarge` and `full-width`; the medium maps those names to suitable dimensions, and `full-width` is the full page in the book and the full content width elsewhere. `float` controls placement and takes `top-left`, `top-right`, `bottom-left`, `bottom-right` or `center`; on a page a float occupies the column measure, so only the vertical half of a corner position has an effect there. The asset remains an Address, so moving the file within its asset root does not change the link. See [assets](assets.md) and [image directives](../reference/format-details.md#images).
|
|
162
|
+
|
|
163
|
+
### Named blocks
|
|
69
164
|
|
|
70
|
-
|
|
71
|
-
|
|
165
|
+
Three named blocks set a passage apart from the prose around it. `:::secret`
|
|
166
|
+
marks GM material, `:::info` a neutral note, and `:::warn` a caution:
|
|
72
167
|
|
|
73
168
|
```markdown
|
|
74
169
|
:::warn
|
|
@@ -76,8 +171,66 @@ The bridge closes during the spring flood.
|
|
|
76
171
|
:::
|
|
77
172
|
```
|
|
78
173
|
|
|
79
|
-
|
|
80
|
-
|
|
174
|
+
Each heads itself with its own name — **Secret**, **Info**, **Warn** — and takes
|
|
175
|
+
a closing `:::`. A name that is not one of the three is reported.
|
|
176
|
+
|
|
177
|
+
**A GM-only section holds a box.** A `:::secret` is a container for whatever the
|
|
178
|
+
GM reads, boxes included, and a box written inside one stays inside it. A box
|
|
179
|
+
holds no named block of its own, so a second box inside a box is reported. A
|
|
180
|
+
`:::figure` fence may be written inside any of them. The two draw a box for
|
|
181
|
+
different reasons: a named block says what kind of aside a passage is, while a
|
|
182
|
+
`:::figure` fence makes a passage numbered and referable — nesting one inside
|
|
183
|
+
the other gives a passage both.
|
|
184
|
+
|
|
185
|
+
**An attribute block follows the name.** It is the same braced grammar the other
|
|
186
|
+
body extensions use, so it carries an id, classes, and any attribute the element
|
|
187
|
+
should have. `title` is reserved and supplies the heading in place of the default:
|
|
188
|
+
|
|
189
|
+
```markdown
|
|
190
|
+
:::secret {#harbor title="For the GM" .wide data-stage="two"}
|
|
191
|
+
The harbor master is working for the smugglers.
|
|
192
|
+
:::
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
That block carries the classes `secret wide`, the id `harbor`, and
|
|
196
|
+
`data-stage="two"`, and it heads **For the GM**. A title carries emphasis of its
|
|
197
|
+
own — `title="The *Genzet* only"` — and nothing else: a tag written there is
|
|
198
|
+
shown rather than obeyed. Set the id with `#id` and classes with `.class` rather
|
|
199
|
+
than through an `id=` or `class=` key, and note that an event handler such as
|
|
200
|
+
`onclick=` is refused rather than written.
|
|
201
|
+
|
|
202
|
+
**The name is the first class on the element, and the appearance belongs to a
|
|
203
|
+
stylesheet.** No block is emitted with an inline `style`, so a package restyles
|
|
204
|
+
one from its own sheet. `info` and `warn` are styled by the base stylesheet;
|
|
205
|
+
`secret` is left to Foundry, which styles `section.secret` itself and owns the
|
|
206
|
+
reveal control on it.
|
|
207
|
+
|
|
208
|
+
Each surface renders the same block its own way:
|
|
209
|
+
|
|
210
|
+
| Surface | Output |
|
|
211
|
+
| ------- | ---------------------------------------------------------------------------------- |
|
|
212
|
+
| Foundry | `<section class="secret" id="harbor">` with the title as its first line |
|
|
213
|
+
| Web | `<details class="secret" id="harbor">` the reader opens, titled in its `<summary>` |
|
|
214
|
+
| Book | a coloured print box headed by the title |
|
|
215
|
+
|
|
216
|
+
A `secret` with no id of its own is given one derived from its body on the
|
|
217
|
+
Foundry surface, because Foundry remembers a revealed section by its id.
|
|
218
|
+
|
|
219
|
+
**A secret is a presentation distinction, not access control.** Players who
|
|
220
|
+
deliberately inspect source or generated output may see it. The
|
|
221
|
+
[detailed reference](../reference/format-details.md#what-a-note-produces)
|
|
222
|
+
describes each medium's handling.
|
|
223
|
+
|
|
224
|
+
**One malformed block does not silence the others.** A block whose attributes do
|
|
225
|
+
not parse is reported at its own line and left as written; every well-formed
|
|
226
|
+
block in the same note still renders.
|
|
227
|
+
|
|
228
|
+
**A heading that would start its own journal page cannot be written inside a
|
|
229
|
+
block, or inside a `:::figure` fence.** An H1, or a heading of any level
|
|
230
|
+
carrying an `{#anchor}`, is reported at its own line there — starting a page
|
|
231
|
+
would tear the block or the figure in two, and a reader could open the second
|
|
232
|
+
half with none of the box around it. A lower heading with no anchor is
|
|
233
|
+
unaffected and is the ordinary way to structure a long box.
|
|
81
234
|
|
|
82
235
|
## Footnotes and definition lists
|
|
83
236
|
|
|
@@ -95,14 +248,19 @@ The road is passable in summer.[^season] The bridge has a toll.[^2]
|
|
|
95
248
|
[^2]: The toll is collected at the eastern gate.
|
|
96
249
|
```
|
|
97
250
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
the
|
|
251
|
+
A reference may be written anywhere prose can be written — a word in a
|
|
252
|
+
quotation, a bullet, a table cell, a heading, a named block, a figure's
|
|
253
|
+
caption. A
|
|
254
|
+
definition belongs at the top level of the note: indent a following paragraph
|
|
255
|
+
or code block by four spaces to include it in the same footnote, but never
|
|
256
|
+
inside a list, a block quote, or a table. A definition written there, or a
|
|
257
|
+
reference with none at the top level to resolve against, is reported at its
|
|
258
|
+
own line rather than rendered. On the web, linked footnotes appear in a
|
|
259
|
+
Footnotes section at the bottom of the HTML page. In Foundry, each
|
|
260
|
+
JournalEntryPage places its referenced footnotes in a Footnotes section at the
|
|
261
|
+
bottom of that page; definitions remain available across pages of the same
|
|
262
|
+
note. In a book, footnotes appear in smaller type at the bottom of the page
|
|
263
|
+
that contains their reference.
|
|
106
264
|
|
|
107
265
|
A definition list gives a term one or more definitions:
|
|
108
266
|
|
|
@@ -115,9 +273,19 @@ Janapada
|
|
|
115
273
|
The web and Foundry render a definition list with HTML `<dl>`, `<dt>`, and
|
|
116
274
|
`<dd>` elements. The book renders it as a term list.
|
|
117
275
|
|
|
118
|
-
##
|
|
276
|
+
## Lists
|
|
277
|
+
|
|
278
|
+
A list item's text begins right after its marker. `[ ]` and `[x]` there are
|
|
279
|
+
plain words, not a checkbox — write what is done into the item itself:
|
|
280
|
+
|
|
281
|
+
```markdown
|
|
282
|
+
- the harbor toll: paid
|
|
283
|
+
- the ferry crossing: owed
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## SQL generated tables
|
|
119
287
|
|
|
120
|
-
|
|
288
|
+
A fence marked `sql` is replaced by a table built from the content index. The query reads the frontmatter of every indexed note, so a table is written once and stays true as notes are added.
|
|
121
289
|
|
|
122
290
|
````markdown
|
|
123
291
|
```sql
|
|
@@ -125,13 +293,135 @@ SELECT name.full AS "Name" FROM notes WHERE type = 'lore' ORDER BY name.full
|
|
|
125
293
|
```
|
|
126
294
|
````
|
|
127
295
|
|
|
128
|
-
|
|
296
|
+
A column's heading is its SQL alias, so `AS "Name"` is what a reader sees. A cell that is absent prints an em dash. A `|` or a line break inside a value is escaped, so neither breaks the table.
|
|
297
|
+
|
|
298
|
+
### What a query can read
|
|
299
|
+
|
|
300
|
+
| Relation | What it holds |
|
|
301
|
+
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
302
|
+
| `notes` | Every note except a stub. This is the one to use unless a stub is wanted. |
|
|
303
|
+
| `entries` | Every note, stubs included. |
|
|
304
|
+
| `market` | The market scale as three columns — `value`, `name`, `trade` — so a table can print `village` beside the number a note wrote. |
|
|
305
|
+
| `<package>.notes` | The same two relations for each package this one declares a dependency on, in a schema named for it. |
|
|
306
|
+
|
|
307
|
+
Nested frontmatter is addressed exactly as a note writes it: `name.full`, `sohl.weight`, `data.born`. Every note carries a computed `state` column of `full`, `draft` or `stub`. Notes tagged `gm` are absent from the relations on public surfaces.
|
|
308
|
+
|
|
309
|
+
### Fence attributes
|
|
310
|
+
|
|
311
|
+
A braced list may follow the language on the opening fence. Two attributes are accepted, and anything else is reported by name.
|
|
312
|
+
|
|
313
|
+
| Attribute | Value | Default | What it does |
|
|
314
|
+
| --------------- | --------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
315
|
+
| `allow-empty` | `true` or `false` | `false` | Whether a query selecting no rows is allowed. A zero-row result is a finding otherwise, because a table that silently prints nothing is the commonest way a query goes wrong unnoticed. |
|
|
316
|
+
| `section-level` | an integer from 1 through 6 | `2` | The heading level given to each group a `_section` column creates. |
|
|
317
|
+
|
|
318
|
+
````markdown
|
|
319
|
+
```sql {allow-empty=true section-level=3}
|
|
320
|
+
SELECT name.full AS "Name" FROM notes WHERE type = 'being' AND data.gender = 'none'
|
|
321
|
+
```
|
|
322
|
+
````
|
|
323
|
+
|
|
324
|
+
A zero-row result reports which relation was queried: a query over `notes` that would have found rows in `entries` says so, so the fix is `FROM entries` rather than `{allow-empty=true}`.
|
|
325
|
+
|
|
326
|
+
### Two column names the renderer reads
|
|
327
|
+
|
|
328
|
+
Two aliases are instructions rather than columns, and neither is printed.
|
|
329
|
+
|
|
330
|
+
| Alias | What it does |
|
|
331
|
+
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
332
|
+
| `_ref` | The note a row points at, written as the `type-shortcode` address a wikilink resolves. The row's first column becomes a link to that note. |
|
|
333
|
+
| `_section` | Partitions the result into separate tables, each under a heading of its own. Order the query by the same expression, because a group ends where the value changes. |
|
|
334
|
+
|
|
335
|
+
```sql
|
|
336
|
+
SELECT type AS "_section", name.full AS "Name", address.slug AS "_ref"
|
|
337
|
+
FROM notes WHERE type IN ('lore', 'place') ORDER BY type, name.full
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
See [SQL details](../reference/format-details.md#content-tables) for query options.
|
|
341
|
+
|
|
342
|
+
## Page lists
|
|
343
|
+
|
|
344
|
+
A fence marked `pagelist` is replaced by a list of the pages carrying a tag. Where a content table answers "what do these notes say?", a page list answers "which pages belong to this group?" — and the group is expressed by intent rather than enumerated, so a page joins it by being tagged and leaves it by being untagged.
|
|
345
|
+
|
|
346
|
+
````markdown
|
|
347
|
+
```pagelist {tag="key-concept"}
|
|
348
|
+
|
|
349
|
+
```
|
|
350
|
+
````
|
|
351
|
+
|
|
352
|
+
**The fence holds nothing.** Everything the directive says about itself is written in the braced attribute block, in the same grammar every other body extension uses. Text written inside the fence is reported rather than printed.
|
|
353
|
+
|
|
354
|
+
Each page comes out as a link to the note, so one authored directive reaches a reader as a compendium link in Foundry, a page link on the website, and a page reference in the book. A link into a note tagged `draft` carries the same cue an authored link to it would.
|
|
355
|
+
|
|
356
|
+
### Page-list attributes
|
|
357
|
+
|
|
358
|
+
<!-- page-list-attributes:start -->
|
|
359
|
+
|
|
360
|
+
| Attribute | Value | Default | What it does |
|
|
361
|
+
| -------------- | ----------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
362
|
+
| `tag` | a tag | required | The tag a page carries to join the list. Matched the way `tags:` is read — case and a leading `#` are not significant, the spelling of the tag itself is. |
|
|
363
|
+
| `type` | a note type | every type | Restricts the list to one note type. A page's address is `<type>-<shortcode>`, so the type is what divides the corpus into kinds of page. |
|
|
364
|
+
| `sort` | `name` or `type` | `name` | The order the pages come out in. `name` is alphabetical; `type` groups the note types and orders by name within each. |
|
|
365
|
+
| `descriptions` | `true` or `false` | `false` | Whether each page's `description` follows its link. A page that states none carries its link alone. |
|
|
366
|
+
| `allow-empty` | `true` or `false` | `false` | Whether a tag carried by no page is allowed. It is a finding otherwise, because a heading with nothing under it is how a misspelled tag goes unnoticed. |
|
|
367
|
+
|
|
368
|
+
<!-- page-list-attributes:end -->
|
|
369
|
+
|
|
370
|
+
````markdown
|
|
371
|
+
```pagelist {tag="key-concept" type=lore sort=type descriptions=true}
|
|
372
|
+
|
|
373
|
+
```
|
|
374
|
+
````
|
|
375
|
+
|
|
376
|
+
That list names the `lore` notes tagged `key-concept`, grouped by type and alphabetical within each, with every page's `description` after its link. A page that states no description carries its link alone.
|
|
377
|
+
|
|
378
|
+
**A tag no page carries is a finding** at the fence's own line, naming the tag it looked for. A misspelled tag is the whole of what goes wrong here, and a heading with an empty list under it is how one goes unnoticed. Write `{allow-empty=true}` where a group that is genuinely empty is intended; the directive then leaves nothing behind rather than an empty list.
|
|
379
|
+
|
|
380
|
+
A page list names this package's own pages. A **stub** — a note with an empty body — publishes no page, so it joins no list. A note tagged `gm` is listed in Foundry and left out of the website and the book, exactly as it is left out of a content table's relations.
|
|
381
|
+
|
|
382
|
+
See [page-list details](../reference/format-details.md#page-lists) for the directive's full behaviour.
|
|
383
|
+
|
|
384
|
+
## Expressions
|
|
385
|
+
|
|
386
|
+
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.
|
|
129
387
|
|
|
130
388
|
```markdown
|
|
131
|
-
{{name.full}} was born on {{dateformat
|
|
389
|
+
{{name.full}} was born on {{dateformat data.calendar data.born}}.
|
|
132
390
|
There are {{words (sql "SELECT COUNT(*) FROM notes WHERE type = 'being'")}} beings.
|
|
133
|
-
The index contains {{digits (sql "SELECT COUNT(*) FROM entries")}} entries.
|
|
134
|
-
{{and (gt 3 5) (lt 4 2)}}
|
|
135
391
|
```
|
|
136
392
|
|
|
137
|
-
|
|
393
|
+
### The rules of the construct
|
|
394
|
+
|
|
395
|
+
- **A field that the note does not carry is a finding, not a blank.** Expressions are compiled strictly, so a misspelled path is reported rather than quietly printing nothing.
|
|
396
|
+
- **An expression is one line.** It may not contain a line break or a brace.
|
|
397
|
+
- **A failed expression leaves its own text in the page** and reports the line and column it is written on, so the page is readable and the fault is locatable.
|
|
398
|
+
- **`\{{` writes an expression without evaluating it**, for an example in prose.
|
|
399
|
+
- **`{{{…}}}`, `{{<…}}` and `{{%…}}` are left alone.** A Hugo shortcode is not an expression.
|
|
400
|
+
- **An expression inside a code fence is left alone.**
|
|
401
|
+
- Helpers nest, with the inner call in parentheses: `{{words (sql "…")}}`.
|
|
402
|
+
|
|
403
|
+
### Helpers
|
|
404
|
+
|
|
405
|
+
<!-- expression-helpers:start -->
|
|
406
|
+
|
|
407
|
+
| Helper | Parameters | What it gives you |
|
|
408
|
+
| ------------ | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
409
|
+
| `eq` | `a b` | True when both are the same value. Compares exactly, so 1 and "1" differ. |
|
|
410
|
+
| `gt` | `a b` | True when a is greater than b. Both must be finite numbers. |
|
|
411
|
+
| `gte` | `a b` | True when a is greater than or equal to b. Both must be finite numbers. |
|
|
412
|
+
| `lt` | `a b` | True when a is less than b. Both must be finite numbers. |
|
|
413
|
+
| `lte` | `a b` | True when a is less than or equal to b. Both must be finite numbers. |
|
|
414
|
+
| `not` | `value` | True when the value is false, zero, empty or absent. |
|
|
415
|
+
| `and` | `value …` | True when every value given is true. Takes two or more. |
|
|
416
|
+
| `or` | `value …` | True when any value given is true. Takes two or more. |
|
|
417
|
+
| `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. |
|
|
418
|
+
| `digits` | `number` | The number as a grouped numeral — `1200` becomes 1,200, and a fractional part is kept. |
|
|
419
|
+
| `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. |
|
|
420
|
+
| `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. |
|
|
421
|
+
| `ref` | `address [form="number"\|"full"\|"title"]` | A link to a `:::figure` fence, 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. |
|
|
422
|
+
|
|
423
|
+
<!-- expression-helpers:end -->
|
|
424
|
+
|
|
425
|
+
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.
|
|
426
|
+
|
|
427
|
+
See [date rules](dates-and-calendars.md) for what `dateformat` accepts and the patterns its third argument names.
|
package/docs/commands.md
CHANGED
|
@@ -1455,15 +1455,17 @@ package-build deps fetch [--from <zip|dir>] [--id <id>]
|
|
|
1455
1455
|
**DESCRIPTION**
|
|
1456
1456
|
|
|
1457
1457
|
The only action is `fetch`, which fills three caches under `build/cache/`:
|
|
1458
|
-
the **content index** of every declared dependency, the **item catalogue
|
|
1459
|
-
of those that additionally declare `itemCatalog: true
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
is
|
|
1465
|
-
|
|
1466
|
-
|
|
1458
|
+
the **content index** of every declared dependency, the **item catalogue or
|
|
1459
|
+
asset archive** of those that additionally declare `itemCatalog: true` or
|
|
1460
|
+
`assetArchive: true`, and the **site navigation** —
|
|
1461
|
+
`https://www.heroiclands.org/nav.json`, the header menu every package site
|
|
1462
|
+
renders, fetched for every package because every package publishes a site.
|
|
1463
|
+
A relationship declaring both `itemCatalog: true` and `assetArchive: true`
|
|
1464
|
+
is fetched once. Its own command rather than a step of `package compile` or
|
|
1465
|
+
`site`, so neither reaches the network — a build that downloads silently is
|
|
1466
|
+
not reproducible and hides a dependency's version change behind a passing
|
|
1467
|
+
run. Each cache is stamped complete only once its fetch finishes, so a
|
|
1468
|
+
half-finished one reads as cold.
|
|
1467
1469
|
|
|
1468
1470
|
`lint`, `links`, `site`, `pdf`, `map`, `reachability`, and `package compile`
|
|
1469
1471
|
check the declared dependencies' content-index cache before reading notes or
|
|
@@ -1501,7 +1503,7 @@ including when the repository declares no dependencies at all.
|
|
|
1501
1503
|
```
|
|
1502
1504
|
$ package-build deps fetch
|
|
1503
1505
|
[…] Fetched the site navigation to build/cache/navigation/nav.json.
|
|
1504
|
-
[…] No relationship declares `itemCatalog: true`; nothing to fetch.
|
|
1506
|
+
[…] No relationship declares `itemCatalog: true` or `assetArchive: true`; nothing to fetch.
|
|
1505
1507
|
[…] This package declares no dependencies.
|
|
1506
1508
|
|
|
1507
1509
|
$ package-build deps fetch --from build/dist/module.zip
|