@heroiclands/package-build 21.0.0 → 21.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/CHANGELOG.md +228 -0
  2. package/CONTENT.md +109 -7
  3. package/assets/fonts/libertinus/LibertinusMono-Regular.otf +0 -0
  4. package/assets/fonts/libertinus/LibertinusSans-Bold.otf +0 -0
  5. package/assets/fonts/libertinus/LibertinusSans-Italic.otf +0 -0
  6. package/assets/fonts/libertinus/LibertinusSans-Regular.otf +0 -0
  7. package/assets/fonts/libertinus/OFL.txt +94 -0
  8. package/assets/fonts/libertinus/provenance.yaml +11 -0
  9. package/assets/images/banners/afflictionbnr.webp +0 -0
  10. package/assets/images/banners/armorclothingbnr.webp +0 -0
  11. package/assets/images/banners/attributebnr.webp +0 -0
  12. package/assets/images/banners/containerbnr.webp +0 -0
  13. package/assets/images/banners/devdocsbnr.webp +0 -0
  14. package/assets/images/banners/miscgearbnr.webp +0 -0
  15. package/assets/images/banners/mysticalabilitybnr.webp +0 -0
  16. package/assets/images/banners/projectilebnr.webp +0 -0
  17. package/assets/images/banners/rulesbnr.webp +0 -0
  18. package/assets/images/banners/skillbnr.webp +0 -0
  19. package/assets/images/banners/traumabnr.webp +0 -0
  20. package/assets/images/banners/userguidebnr.webp +0 -0
  21. package/assets/images/banners/weapongearbnr.webp +0 -0
  22. package/assets/images/provenance.yaml +4 -0
  23. package/bin/content-build.mjs +19 -5
  24. package/ci/emit-asset-index.mjs +32 -0
  25. package/content-config.mjs +30 -1
  26. package/docs/api.md +100 -26
  27. package/docs/configuration.md +16 -7
  28. package/docs/content-format.md +512 -109
  29. package/engine/actor-compiler.mjs +58 -9
  30. package/engine/art-fields.mjs +292 -0
  31. package/engine/asset-index.mjs +397 -0
  32. package/engine/asset-types.mjs +192 -0
  33. package/engine/base-compiler.mjs +69 -1
  34. package/engine/bundles.mjs +5 -5
  35. package/engine/compile-corpus.mjs +4 -0
  36. package/engine/content-address.mjs +14 -2
  37. package/engine/content-charset.mjs +5 -1
  38. package/engine/content-embeds.mjs +314 -0
  39. package/engine/content-html.mjs +5 -1
  40. package/engine/content-icons.mjs +5 -1
  41. package/engine/content-images.mjs +26 -5
  42. package/engine/content-index.mjs +68 -33
  43. package/engine/content-links.mjs +164 -24
  44. package/engine/frontmatter-lint.mjs +36 -23
  45. package/engine/helpers.mjs +83 -31
  46. package/engine/index-records.mjs +63 -4
  47. package/engine/index.mjs +15 -0
  48. package/engine/infobox-registry.mjs +50 -3
  49. package/engine/infobox-render.mjs +4 -3
  50. package/engine/infobox.mjs +12 -8
  51. package/engine/item-compiler.mjs +10 -10
  52. package/engine/journals.mjs +3 -0
  53. package/engine/macros.mjs +16 -13
  54. package/engine/map-notes.mjs +29 -22
  55. package/engine/metadata-index.mjs +44 -36
  56. package/engine/note-vocabulary.mjs +71 -29
  57. package/engine/pack-router.mjs +14 -0
  58. package/engine/packagebuild-index.mjs +124 -0
  59. package/engine/packages.mjs +83 -0
  60. package/engine/pathnames.mjs +74 -0
  61. package/engine/pdf-build.mjs +133 -10
  62. package/engine/pdf-render.mjs +41 -41
  63. package/engine/scenes.mjs +12 -9
  64. package/engine/site-build.mjs +43 -16
  65. package/engine/site-index.mjs +10 -1
  66. package/engine/subtype-registry.mjs +21 -0
  67. package/engine/web-wikilinks.mjs +46 -12
  68. package/engine/wikilink-syntax.mjs +20 -2
  69. package/engine/wikilinks.mjs +15 -2
  70. package/hm3/actors.mjs +11 -38
  71. package/hm3/infobox.mjs +1 -1
  72. package/package.json +5 -2
  73. package/packagebuild-metadata.jsonl +13 -0
  74. package/sohl/actors.mjs +12 -86
  75. package/sohl/infobox.mjs +1 -1
  76. package/sohl/note-schemas.mjs +4 -16
  77. package/types/content-config.d.mts +8 -0
  78. package/types/engine/actor-compiler.d.mts +29 -0
  79. package/types/engine/art-fields.d.mts +192 -0
  80. package/types/engine/asset-index.d.mts +92 -0
  81. package/types/engine/asset-types.d.mts +110 -0
  82. package/types/engine/base-compiler.d.mts +42 -1
  83. package/types/engine/compile-corpus.d.mts +4 -1
  84. package/types/engine/content-charset.d.mts +4 -0
  85. package/types/engine/content-embeds.d.mts +218 -0
  86. package/types/engine/content-html.d.mts +4 -0
  87. package/types/engine/content-icons.d.mts +4 -0
  88. package/types/engine/content-images.d.mts +15 -2
  89. package/types/engine/content-index.d.mts +27 -15
  90. package/types/engine/frontmatter-lint.d.mts +11 -14
  91. package/types/engine/helpers.d.mts +7 -2
  92. package/types/engine/index-records.d.mts +44 -3
  93. package/types/engine/index.d.mts +5 -0
  94. package/types/engine/infobox-registry.d.mts +36 -1
  95. package/types/engine/infobox.d.mts +6 -4
  96. package/types/engine/macros.d.mts +9 -5
  97. package/types/engine/map-notes.d.mts +10 -6
  98. package/types/engine/metadata-index.d.mts +2 -17
  99. package/types/engine/note-vocabulary.d.mts +30 -0
  100. package/types/engine/packagebuild-index.d.mts +56 -0
  101. package/types/engine/packages.d.mts +62 -0
  102. package/types/engine/pathnames.d.mts +41 -81
  103. package/types/engine/pdf-build.d.mts +58 -1
  104. package/types/engine/pdf-render.d.mts +3 -3
  105. package/types/engine/scenes.d.mts +2 -1
  106. package/types/engine/site-build.d.mts +5 -1
  107. package/types/engine/site-index.d.mts +4 -1
  108. package/types/engine/subtype-registry.d.mts +20 -0
  109. package/types/engine/web-wikilinks.d.mts +14 -4
  110. package/types/engine/wikilink-syntax.d.mts +13 -1
  111. package/types/engine/wikilinks.d.mts +7 -1
  112. package/types/sohl/actors.d.mts +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,233 @@
1
1
  # @heroiclands/package-build
2
2
 
3
+ ## 21.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 9ccd9e1: **Art and sound have addresses** — A package's pictures and sound clips are now
8
+ addressed the way its notes are. `icon`, `image` and `audio` are types a
9
+ reference can reach, one per tree: `assets/icons`, `assets/images` and
10
+ `assets/audio`. The filename is the name — `anvil.svg` is `icon-anvil` — and the
11
+ directories above it are the package's own business, so a tree can be tidied
12
+ into whatever arrangement suits the people who maintain it without a single
13
+ reference changing.
14
+
15
+ - _The extension stays out of the name._ Changing a picture from SVG to WebP is
16
+ dropping a different file in place; nothing that names it has to be touched.
17
+ - _Two files cannot claim one name._ A root's names are one list however deeply
18
+ it nests, and the build says which two files collided.
19
+ - _Attribution travels with the file._ Who made it, where it came from and what
20
+ licence it carries are published beside it, taken from the `provenance.yaml`
21
+ nearest the file or from a record written for that one file alone.
22
+ - _A package can lend its art._ Every address says which package holds the
23
+ bytes, so a picture one package ships resolves for another that cites it — on
24
+ the website, in the book, and in Foundry.
25
+ - `packagebuild` is a reserved name, held for the files the toolchain itself
26
+ ships, so no package may claim it.
27
+
28
+ Fonts are deliberately not addressable: nobody names a typeface the way they
29
+ name a picture, and a stylesheet and a typesetter each want something an address
30
+ cannot give them.
31
+ - 888f64a: **An image a Foundry journal cannot serve is refused** — An image in a note's
32
+ body names the package that owns the file, and a journal can only draw one from
33
+ a package the install carries. An address naming a package the build declares no
34
+ relationship with — or `packagebuild`, whose shared banners travel with the
35
+ toolchain and belong to the website and the book — is reported with the file,
36
+ line and column it sits on, and the build stops rather than compiling a document
37
+ whose picture resolves against nothing.
38
+
39
+ - _Both spellings, one answer._ `![alt](…)` and `![[address|label]]` are one
40
+ image, so an address is refused in the same words whichever way it is written.
41
+ - _`banner:` is where a shared banner belongs._ It reaches the page and the
42
+ book's section plates and no compiled document, so a note plating a section
43
+ with one of the toolchain's banners is doing the right thing.
44
+ - _An address naming no package still passes through._ A URL, a
45
+ protocol-relative `//host/…`, a `data:` URI and a `/`-rooted path reach a
46
+ journal untouched, which is how a note draws core Foundry art or art from a
47
+ package outside this constellation.
48
+ - b34686f: **The shared banners can be named from anywhere** — A note borrows one of the
49
+ section banners the toolchain ships by naming it, and nothing has to be declared
50
+ or downloaded first:
51
+
52
+ ```yaml
53
+ data:
54
+ banner: packagebuild-none-image-skillbnr
55
+ ```
56
+
57
+ The pictures travel with the toolchain itself, so a package plates a section
58
+ without keeping its own copy and without taking on a dependency on some parent
59
+ system it has no other relationship with. They appear on the website and in the
60
+ book; Foundry installs nothing for them, which is why nothing in a compendium
61
+ ever names one.
62
+
63
+ `packagebuild` is reserved, so no package can claim the name out from under
64
+ them.
65
+ - 9a937e7: **A note names its art, and the art arrives** — The picture a document carries
66
+ is chosen by name now, the way everything else in a note is. `icon` is what a
67
+ directory listing shows beside the name, `tokenIcon` what a token on the canvas
68
+ wears, `bgImage` a map's background, and `banner` the hero image at the top of a
69
+ page. Write the name of the file and the build finds it.
70
+
71
+ - _The art actually reaches the document._ Every compiled item took its type's
72
+ stock picture whatever its note said; it now carries the one it names, and the
73
+ same goes for a being's profile art, its token and its portrait.
74
+ - _A map is art all through._ Its background, the pictures on its tiles and the
75
+ sound clips placed around it are all named the same way and all resolved.
76
+ - _A being with no picture of its own gets one that suits it_ — a person and a
77
+ creature fall back to different art, chosen from what the note says it is.
78
+ - _A picture one package ships reaches another that names it_, on the website,
79
+ in the book and in Foundry, with each getting the address it serves.
80
+ - _`tokenIcon` unset follows `icon`._ A being naming one picture wears it on the
81
+ canvas too.
82
+ - _A name nothing answers is reported against the note_ rather than quietly
83
+ becoming the stock picture.
84
+
85
+ A being's portrait is the first image inside its `{#appearance}` section now,
86
+ written in the prose that describes it rather than declared in a field — where
87
+ an author can see it, move it and caption it like any other picture.
88
+ - 7661355: **A picture goes where it belongs in the prose** — `![[address|label]]` puts an
89
+ image where it is written, and every surface draws it there: a Foundry journal,
90
+ the website and the book alike. It is the wikilink already in use, with `!`
91
+ meaning _draw it here_ rather than _link to it_, so nothing new has to be
92
+ learned — the same short form, the same way of reaching another package's
93
+ artwork, the same complaint when an address names nothing.
94
+
95
+ - _The label is what the picture says._ It is the caption in print, and the
96
+ words a screen reader announces when the image does not load. `![[anvil|]]`
97
+ says the picture is decoration and needs none.
98
+ - _It sits where it is told._ An embed takes the same `{…}` an image does — a
99
+ width, a position, or both in either order — and an unrecognised value is
100
+ refused with the file and line it is on rather than quietly ignored.
101
+ - _Only a picture can be embedded._ Naming a character or a skill where a file
102
+ belongs is refused, and the message says to link to it instead.
103
+ - _A being's portrait opens its appearance._ Every creature and every character
104
+ now shows its picture at the top of what it looks like, in the compendium, on
105
+ the page and in the book.
106
+ - 84a6715: **Shared section banners** — package-build now ships the thirteen banner images
107
+ many packages draw on, and publishes them to consumers. A package can plate a
108
+ section without keeping its own copy, and without declaring a dependency on some
109
+ parent system or module to borrow one.
110
+
111
+ They are licensed CC-BY-SA-4.0, recorded beside them.
112
+ - 0c10ba5: **Everything a being carries now has a picture** — Gear and skills written out
113
+ inside a being's note, rather than copied from the catalogue, reached the sheet
114
+ with no artwork at all. They carry art now, by the same two rules everything
115
+ else does.
116
+
117
+ - _An item can name its own._ Write an icon under `data:` and the sheet shows it.
118
+ - _And it takes one when it names none._ A whetstone somebody wrote out by hand
119
+ gets the picture every other piece of miscellaneous gear gets, instead of a
120
+ blank.
121
+ - fc33f24: **The book sets in the faces the build carries, not the ones the machine has.**
122
+ Headings, running heads, table labels and captions are set in _Libertinus Sans_
123
+ — the toolchain ships it, so a book sets the same way on any machine, and the
124
+ sans no longer comes out in the body face because nothing could resolve it.
125
+ _Libertinus Mono_ is shipped beside it for a package that sets its code spans in
126
+ it; the default mono is unchanged.
127
+
128
+ **A face that resolves to nothing is reported.** A compile that cannot find a
129
+ family still writes a book, set in whatever the fallback reached — a wrong face
130
+ that nobody sees. The compiler's warnings are now findings like any other, with
131
+ the file, the line and the column.
132
+
133
+ ### Patch Changes
134
+
135
+ - d2d029a: **A system panel says what the module actually ships** — A page's SoHL or HM3
136
+ box reads _Not available_ only where that system really has no document for the
137
+ note, which is what a reader acts on.
138
+
139
+ - _A note need not name a system to have one._ Where the whole of a subject
140
+ lives in its own fields — an affiliation, a being written without system
141
+ detail — the panel now carries the subject's fields instead of claiming the
142
+ page is outside the system's reach.
143
+ - _A system the module ships nothing for still says so_, on every page that
144
+ could have carried it.
145
+ - 9d4ba48: **Content format** — A map names its art the way every other note does. Its
146
+ background is `bgImage`, an `image` address; a tile names its art with `image`
147
+ and an ambient sound names its clip with `audio`. A map carries no `img` — a
148
+ Scene has no such field.
149
+ - acea050: **Content format** — The specification describes art as addresses rather than
150
+ file paths. A note names its artwork with a wikilink address, an asset lives at
151
+ an address that holds exactly one file with the extension outside the name, and
152
+ `icon`, `image`, `font` and `audio` are types a link can reach like any other.
153
+
154
+ - The five art slots are `icon`, `portrait`, `tokenIcon`, `bgImage` and
155
+ `banner`, each a wikilink field with its own default type.
156
+ - An image in a note's body is written `![[address|alt text]]`, an empty label
157
+ marking it decorative.
158
+ - `packagebuild` is reserved, so any package can name a shared section banner
159
+ without declaring a dependency to reach it.
160
+
161
+ The build reads art as file paths, so it refuses a tree written to this
162
+ specification. The specification is the target; the build is what runs today.
163
+ - 60815eb: **A lint finding opens where it says it is** — Every path a content lint prints
164
+ is relative to the directory the command was run from, so one `content-build
165
+ lint` run reports every finding in the same shape and each one opens in an
166
+ editor, a CI annotation or a `$EDITOR +line` jump.
167
+
168
+ - _Characters, icons, raw HTML and image directives_ report the note's path the
169
+ way the address and frontmatter rules beside them already do.
170
+ - 7d79e70: **Content format** — A being's portrait is a picture in its prose, not a field.
171
+ It opens the note's `{#appearance}` section — the **lead image** — and
172
+ `data.portrait` is gone:
173
+
174
+ ```markdown
175
+ # Appearance {#appearance}
176
+
177
+ ![[branwldrgr|Brànwâal Dôrgaar]]{float: top-left}
178
+ ```
179
+
180
+ Nothing about that embed is special: it is an ordinary embedded image with an
181
+ ordinary directive, and the strictness is the convention that the portrait opens
182
+ the section, so every being note reads the same way. The section matters as well
183
+ as the order — `{#appearance}` is what becomes an actor's appearance, so a
184
+ picture above that heading reaches no document. An author can move it, caption it
185
+ or drop it like any other picture.
186
+
187
+ Four art slots remain — `icon`, `tokenIcon`, `bgImage` and `banner` — each
188
+ naming art that a document field needs. An embed also takes the same `{…}`
189
+ directive an image does, so a float or a width applies to either.
190
+ - d6d837c: **Content format** — An asset's address is derived from where its file sits.
191
+ Three roots, one per type — `assets/icons`, `assets/images` and `assets/audio` —
192
+ and any file with a matching extension anywhere beneath one is an asset of that
193
+ type, however deep. The filename is the shortcode, the
194
+ extension is not part of the address, and the directories in between are the
195
+ package's own business.
196
+
197
+ A root's shortcodes are one flat namespace, so two files under one root sharing
198
+ a basename are a build error naming both. Across roots they are different
199
+ addresses: `icon-anvil` and `image-anvil` name different pictures for different
200
+ purposes.
201
+
202
+ A font is not an asset and has no address. Nothing names a typeface the way a
203
+ note names a picture, and neither consumer of a font could use an address
204
+ anyway: a stylesheet wants a relative `url()` and the book wants a family name.
205
+ Fonts stay ordinary files a package ships and points a tool at.
206
+
207
+ ## 21.1.0
208
+
209
+ ### Minor Changes
210
+
211
+ - 7577722: **Headings in the book**
212
+
213
+ - A heading is set by its depth rather than every heading alike: a note's top-level heading opens large, keeps its underline and takes a clear run of space above it, and each level beneath is smaller and separated by space alone.
214
+ - Headings set in the sans face and in the case they were written in, so a section reads as words rather than as tracked capitals. A book that names no sans face still sets them in its book face, exactly as before.
215
+ - A parent section and the sections inside it can be told apart at a glance, without reading the words.
216
+ - 57fee4c: **Infobox panels in the book**
217
+
218
+ - Each panel is drawn as a closed box — a light border on all four sides over a tint a step below the paper — so a page carrying Profile, system and appearance panels reads as a stack of cards rather than a run of rules.
219
+ - Skill and equipment groups stand apart from one another, so a group that wraps onto a second line is no longer mistaken for the start of the next one.
220
+
221
+ **Naming the systems**
222
+
223
+ - The system panels are titled _Song of Heroic Lands_ and _HârnMaster 3_ in full, in the book and on the web, in place of the abbreviations.
224
+
225
+ ### Patch Changes
226
+
227
+ - 705cdc8: **The book** — an entry's first paragraph sets like any other. A raised opening
228
+ letter is something a note asks for, not something the book decides on its
229
+ own, so nothing raises one.
230
+
3
231
  ## 21.0.0
4
232
 
5
233
  ### Major Changes
package/CONTENT.md CHANGED
@@ -100,6 +100,9 @@ icons: assets/icon-registry.yaml
100
100
  # conventional layout shown here.
101
101
  paths:
102
102
  content: assets/content
103
+ # The asset roots' parent: `icons/`, `images/` and `audio/` sit directly under
104
+ # it, and the content tree beside them.
105
+ assets: assets
103
106
  # Vendored foreign manifests, read by `links`. Inbound.
104
107
  manifests: assets/manifests
105
108
  # Where `manifest` writes this package's own. Outbound, and a build artifact.
@@ -1778,6 +1781,32 @@ asked for — a build that downloads silently is not reproducible and fails
1778
1781
  strangely offline. The cache is keyed by version, so changing the pinned version
1779
1782
  is a miss rather than a silent overwrite.
1780
1783
 
1784
+ ### `packagebuild` needs no declaration
1785
+
1786
+ package-build ships a set of images of its own — section banners chiefly — and a
1787
+ note reaches one without declaring anything:
1788
+
1789
+ ```yaml
1790
+ data:
1791
+ banner: packagebuild-none-image-skillbnr
1792
+ ```
1793
+
1794
+ **There is nothing to declare and nothing to fetch.** package-build is an npm
1795
+ dependency of every consumer rather than a Foundry package, so there is no
1796
+ release archive behind the name and no reason to fetch one — the tree is already
1797
+ on disk under `node_modules/@heroiclands/package-build/assets/`. The records are
1798
+ walked from it on every load and join the index like any other package's, so a
1799
+ cold cache is not a failure mode here and every lookup stays one path.
1800
+
1801
+ `packagebuild` is a **reserved** name: no repository may configure it as its
1802
+ `contentPackage`, and a configuration that tries is refused.
1803
+
1804
+ **These addresses have no Foundry form.** Foundry installs no package for this
1805
+ one, so a resolver returns "no Foundry address" deliberately rather than
1806
+ deriving `modules/packagebuild/…`, which installs nowhere. That is not a
1807
+ limitation in practice: the only slot that names them is `banner`, which reaches
1808
+ no compiled document at all and is read by the website and the book.
1809
+
1781
1810
  **A fetched catalogue is read one system at a time.** A dependency may ship a
1782
1811
  pack per system, and the two hold the same `(type, shortcode)` addresses with
1783
1812
  different data models — `skill:awar` is a real address in both vocabularies and
@@ -1956,17 +1985,59 @@ frontmatter spreads **242 distinct leaf paths** unevenly over **15 types**, from
1956
1985
  authoring. A format with a fixed column set would turn that authoring into a
1957
1986
  schema migration; a document format has no such problem.
1958
1987
 
1959
- Two keys are **derived** rather than authored, and a note carrying either is an
1988
+ Three keys are **derived** rather than authored, and a note carrying one is an
1960
1989
  error rather than a silent overwrite:
1961
1990
 
1962
1991
  | Key | What it holds |
1963
1992
  | --------- | -------------------------------------------------------------------------------------------------- |
1964
1993
  | `package` | The configured `contentPackage`. A note may not declare its own, and the expander reads the same. |
1965
1994
  | `file` | `path`, `folder` and `name` below the content root — the same `file.*` a content-table query uses. |
1995
+ | `asset` | The file an asset record addresses. Present on an asset's record and on no note's. |
1966
1996
 
1967
1997
  The location is namespaced under `file` precisely because `folder` is real
1968
1998
  frontmatter on most notes; a record states both, and they mean different things.
1969
1999
 
2000
+ ### A file is a record too
2001
+
2002
+ The same pass walks the package's **asset roots** — `assets/icons`,
2003
+ `assets/images` and `assets/audio` — and emits one record per addressable file
2004
+ into the same index. There is no second artifact and no asset-specific emitter:
2005
+ a package whose tree holds only pictures publishes an ordinary content index
2006
+ that happens to hold only asset records.
2007
+
2008
+ The filename is the shortcode, the root supplies the type, and the layout in
2009
+ between is the package's own business:
2010
+
2011
+ ```json
2012
+ {
2013
+ "type": "icon",
2014
+ "shortcode": "anvil",
2015
+ "package": "sohl",
2016
+ "address": { "canonical": "sohl-none-icon-anvil" },
2017
+ "asset": {
2018
+ "path": "icons/game-icons/lorc/anvil.svg",
2019
+ "attribution": "Lorc",
2020
+ "source": "http://lorcblog.blogspot.com",
2021
+ "license": "CC-BY-3.0",
2022
+ "notes": "From game-icons.net"
2023
+ }
2024
+ }
2025
+ ```
2026
+
2027
+ An asset record carries no frontmatter, no anchors and no `foundry` block, and
2028
+ its `address` holds the canonical key and no page slug — a file declares nothing
2029
+ about itself, compiles into no document, and publishes no page. The `asset`
2030
+ block is what a reader tells the two shapes apart by.
2031
+
2032
+ `path` is relative to the emitting package's own asset directory, so each
2033
+ consumer joins its own root onto it and resolves in one step. Provenance comes
2034
+ from a sibling `<filename.ext>.yaml` where one exists, and otherwise from the
2035
+ nearest `provenance.yaml` above the file, searching no higher than the type
2036
+ root. `docs/content-format.md` states the whole rule.
2037
+
2038
+ Two files under one root sharing a basename are two claims on one address, and
2039
+ the build fails naming both.
2040
+
1970
2041
  ### Every note's address, and every anchor it defines
1971
2042
 
1972
2043
  A record states the address a wikilink writes to reach the note, and every
@@ -2467,10 +2538,8 @@ alone — a scrolling page has no fixed viewport, so the website keeps one
2467
2538
  measure with a side rail.
2468
2539
 
2469
2540
  A note's `description:` sets as an epigraph between short rules under the
2470
- plate, and the first paragraph of the prose opens on a raised capital. Both
2471
- disappear rather than leave a shell: a note with no description has no
2472
- epigraph, and a body opening on a link or a number keeps its own first
2473
- character. The running foot carries the section's name, an ornament and the
2541
+ plate. It disappears rather than leave a shell: a note with no description has
2542
+ no epigraph. The running foot carries the section's name, an ornament and the
2474
2543
  folio.
2475
2544
 
2476
2545
  A table of **more than three columns** is given an explicit span rather than
@@ -2540,11 +2609,11 @@ pdf:
2540
2609
  out: build/dist # default
2541
2610
  front: # prose before the contents
2542
2611
  - prose/colophon.md
2543
- fonts:
2612
+ fonts: # every key optional — the defaults below
2544
2613
  serif: Libertinus Serif
2545
2614
  sans: Libertinus Sans
2546
2615
  mono: DejaVu Sans Mono
2547
- path: assets/fonts # where to find them, beyond the system's
2616
+ path: assets/fonts # faces of your own, searched as well as the shipped ones
2548
2617
  iconFonts: # icon family → the font carrying its glyphs
2549
2618
  fontawesome: assets/fonts/fa-solid-900.ttf
2550
2619
  binary: typst # when it is not simply `typst` on PATH
@@ -2553,6 +2622,39 @@ pdf:
2553
2622
  Nothing here is an address or a brand: the title, the front matter and the faces
2554
2623
  are the publishing repository's to choose, which is why they are configuration.
2555
2624
 
2625
+ ### The faces come with the build, not with the machine
2626
+
2627
+ All three defaults resolve on a machine that has none of them installed. The
2628
+ serif and the mono the defaults name are faces the compiler embeds; the sans is
2629
+ one the toolchain ships, under `assets/fonts`, along with the superfamily's own
2630
+ mono for a package that names it. The compile searches that directory, and
2631
+ `pdf.fonts.path` when a package names one, and **nothing the machine has
2632
+ installed** — `--font-path` and `--ignore-system-fonts` together — so the same
2633
+ source sets the same book everywhere, and a machine carrying its own copy of a
2634
+ named family does not quietly change what it prints.
2635
+
2636
+ The default mono is the compiler's rather than the superfamily's because the
2637
+ superfamily's mono carries none of the dot-below and dot-above letters this
2638
+ corpus spells names with. A package whose fenced blocks stay inside what it does
2639
+ carry can name it instead, and the compiler reports nothing when a glyph is
2640
+ missing, so that is a claim to measure against the fences rather than assume.
2641
+
2642
+ A face nothing resolves is a **finding** — the compiler says so, and a compile
2643
+ that says it still exits 0 and writes a book set in the fallback, which is the
2644
+ one way a wrong face reaches a reader unnoticed.
2645
+
2646
+ Compiling an emitted `.typ` by hand takes the same two flags to set it the way
2647
+ the build does:
2648
+
2649
+ ```bash
2650
+ typst compile --ignore-system-fonts \
2651
+ --font-path node_modules/@heroiclands/package-build/assets/fonts \
2652
+ build/dist/the-book.typ
2653
+ ```
2654
+
2655
+ The shipped face is licensed under the SIL Open Font License, which travels with
2656
+ it.
2657
+
2556
2658
  ### Typst is a binary, not a dependency
2557
2659
 
2558
2660
  The compiler is an external program, found on `PATH` or named by `pdf.binary`.
@@ -0,0 +1,94 @@
1
+ Copyright © 2012-2024 The Libertinus Project Authors,
2
+ with Reserved Font Name "Linux Libertine", "Biolinum", "STIX Fonts".
3
+
4
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
5
+ This license is copied below, and is also available with a FAQ at:
6
+ http://scripts.sil.org/OFL
7
+
8
+
9
+ -----------------------------------------------------------
10
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
11
+ -----------------------------------------------------------
12
+
13
+ PREAMBLE
14
+ The goals of the Open Font License (OFL) are to stimulate worldwide
15
+ development of collaborative font projects, to support the font creation
16
+ efforts of academic and linguistic communities, and to provide a free and
17
+ open framework in which fonts may be shared and improved in partnership
18
+ with others.
19
+
20
+ The OFL allows the licensed fonts to be used, studied, modified and
21
+ redistributed freely as long as they are not sold by themselves. The
22
+ fonts, including any derivative works, can be bundled, embedded,
23
+ redistributed and/or sold with any software provided that any reserved
24
+ names are not used by derivative works. The fonts and derivatives,
25
+ however, cannot be released under any other type of license. The
26
+ requirement for fonts to remain under this license does not apply
27
+ to any document created using the fonts or their derivatives.
28
+
29
+ DEFINITIONS
30
+ "Font Software" refers to the set of files released by the Copyright
31
+ Holder(s) under this license and clearly marked as such. This may
32
+ include source files, build scripts and documentation.
33
+
34
+ "Reserved Font Name" refers to any names specified as such after the
35
+ copyright statement(s).
36
+
37
+ "Original Version" refers to the collection of Font Software components as
38
+ distributed by the Copyright Holder(s).
39
+
40
+ "Modified Version" refers to any derivative made by adding to, deleting,
41
+ or substituting -- in part or in whole -- any of the components of the
42
+ Original Version, by changing formats or by porting the Font Software to a
43
+ new environment.
44
+
45
+ "Author" refers to any designer, engineer, programmer, technical
46
+ writer or other person who contributed to the Font Software.
47
+
48
+ PERMISSION & CONDITIONS
49
+ Permission is hereby granted, free of charge, to any person obtaining
50
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
51
+ redistribute, and sell modified and unmodified copies of the Font
52
+ Software, subject to the following conditions:
53
+
54
+ 1) Neither the Font Software nor any of its individual components,
55
+ in Original or Modified Versions, may be sold by itself.
56
+
57
+ 2) Original or Modified Versions of the Font Software may be bundled,
58
+ redistributed and/or sold with any software, provided that each copy
59
+ contains the above copyright notice and this license. These can be
60
+ included either as stand-alone text files, human-readable headers or
61
+ in the appropriate machine-readable metadata fields within text or
62
+ binary files as long as those fields can be easily viewed by the user.
63
+
64
+ 3) No Modified Version of the Font Software may use the Reserved Font
65
+ Name(s) unless explicit written permission is granted by the corresponding
66
+ Copyright Holder. This restriction only applies to the primary font name as
67
+ presented to the users.
68
+
69
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
70
+ Software shall not be used to promote, endorse or advertise any
71
+ Modified Version, except to acknowledge the contribution(s) of the
72
+ Copyright Holder(s) and the Author(s) or with their explicit written
73
+ permission.
74
+
75
+ 5) The Font Software, modified or unmodified, in part or in whole,
76
+ must be distributed entirely under this license, and must not be
77
+ distributed under any other license. The requirement for fonts to
78
+ remain under this license does not apply to any document created
79
+ using the Font Software.
80
+
81
+ TERMINATION
82
+ This license becomes null and void if any of the above conditions are
83
+ not met.
84
+
85
+ DISCLAIMER
86
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
87
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
88
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
89
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
90
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
91
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
92
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
93
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
94
+ OTHER DEALINGS IN THE FONT SOFTWARE.
@@ -0,0 +1,11 @@
1
+ attribution: The Libertinus Project Authors
2
+ source: https://github.com/alerque/libertinus/releases/tag/v7.051
3
+ license: OFL-1.1
4
+ notes: >-
5
+ Libertinus Sans in the three styles a heading can ask for, and Libertinus
6
+ Mono, which a package may name for its code spans. Taken unmodified from the
7
+ release's static/OTF directory; the licence text travels with them as
8
+ OFL.txt, as the OFL requires. The serif half of the superfamily is not here
9
+ because the compiler embeds it, and the remaining faces of the release —
10
+ Math, Display, Initials, Keyboard and the Semibold weights — are ones no
11
+ book sets.
@@ -0,0 +1,4 @@
1
+ attribution: Tom Rodriguez
2
+ source: ""
3
+ license: CC-BY-SA-4.0
4
+ notes: ""
@@ -969,6 +969,10 @@ function lintCommand() {
969
969
  // so these are errors and they fail the run.
970
970
  const images = lintContentImages(root, {
971
971
  skipDirectories: config.skipDirectories,
972
+ // Which packages this build can reach is configuration, and
973
+ // an address naming one it cannot reaches a journal as a
974
+ // path that resolves against nothing.
975
+ config,
972
976
  });
973
977
 
974
978
  const findings = [
@@ -1250,6 +1254,7 @@ function linksCommand() {
1250
1254
  const {
1251
1255
  deadAnchors,
1252
1256
  deadAddresses,
1257
+ deadEmbeds,
1253
1258
  unlabelledLinks,
1254
1259
  frontmatterLinks,
1255
1260
  homepageLinks,
@@ -1271,12 +1276,15 @@ function linksCommand() {
1271
1276
  // differently because the corrections differ. The wording comes
1272
1277
  // from the shared table, so the checker cannot describe a
1273
1278
  // defect differently from the build that also refuses it.
1274
- for (const d of [...deadAddresses, ...unlabelledLinks]) {
1279
+ for (const d of [...deadAddresses, ...unlabelledLinks, ...deadEmbeds]) {
1275
1280
  emitDiagnostic({
1276
1281
  file: d.note.file,
1277
1282
  ...positionOfLiteral(d.note.raw, d.text, d.occurrence),
1278
1283
  severity: "error",
1279
- message: linkFindingMessage(d),
1284
+ // An embed's directive speaks the image vocabulary and
1285
+ // carries its own sentence; everything else is worded
1286
+ // by the shared table.
1287
+ message: d.message ?? linkFindingMessage(d),
1280
1288
  });
1281
1289
  }
1282
1290
  for (const f of frontmatterLinks) {
@@ -1306,6 +1314,7 @@ function linksCommand() {
1306
1314
  const failures =
1307
1315
  deadAnchors.length +
1308
1316
  deadAddresses.length +
1317
+ deadEmbeds.length +
1309
1318
  unlabelledLinks.length +
1310
1319
  frontmatterLinks.length +
1311
1320
  homepageLinks.length;
@@ -1315,8 +1324,9 @@ function linksCommand() {
1315
1324
  } else {
1316
1325
  log.info(
1317
1326
  `${index.notes.length} notes: every link is a labelled ` +
1318
- `address, every anchor link lands and every ` +
1319
- `address resolves (${usedManifest.size} ` +
1327
+ `address, every embed names a file, every anchor ` +
1328
+ `link lands and every address resolves ` +
1329
+ `(${usedManifest.size} ` +
1320
1330
  `cross-package reference(s) via manifest), no ` +
1321
1331
  `wikilink in frontmatter, every homepage address ` +
1322
1332
  `resolvable.`,
@@ -1576,7 +1586,11 @@ function siteCommand() {
1576
1586
  file: e.file,
1577
1587
  ...positionOfLiteral(readRawNote(e.file), e.link, e.occurrence),
1578
1588
  severity: "error",
1579
- message: linkFindingMessage(e),
1589
+ // An embed's directive speaks the image vocabulary
1590
+ // rather than the link one, and carries its own
1591
+ // sentence; everything else is worded by the shared
1592
+ // table.
1593
+ message: e.message ?? linkFindingMessage(e),
1580
1594
  });
1581
1595
  }
1582
1596
  // An image whose pathname the site cannot resolve, located the