@heroiclands/package-build 21.1.0 → 22.0.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 (115) hide show
  1. package/CHANGELOG.md +245 -0
  2. package/CONTENT.md +107 -3
  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/bin/package-build.mjs +6 -5
  25. package/ci/emit-asset-index.mjs +32 -0
  26. package/content-config.mjs +30 -1
  27. package/docs/api.md +103 -27
  28. package/docs/commands.md +13 -11
  29. package/docs/configuration.md +16 -7
  30. package/docs/content-format.md +523 -111
  31. package/engine/actor-compiler.mjs +58 -9
  32. package/engine/art-fields.mjs +292 -0
  33. package/engine/asset-index.mjs +397 -0
  34. package/engine/asset-types.mjs +192 -0
  35. package/engine/base-compiler.mjs +69 -1
  36. package/engine/bundles.mjs +5 -5
  37. package/engine/compile-corpus.mjs +4 -0
  38. package/engine/content-address.mjs +14 -2
  39. package/engine/content-charset.mjs +5 -1
  40. package/engine/content-embeds.mjs +314 -0
  41. package/engine/content-html.mjs +5 -1
  42. package/engine/content-icons.mjs +5 -1
  43. package/engine/content-images.mjs +26 -5
  44. package/engine/content-index.mjs +68 -33
  45. package/engine/content-links.mjs +164 -24
  46. package/engine/dependency-bump.mjs +14 -16
  47. package/engine/frontmatter-lint.mjs +36 -23
  48. package/engine/helpers.mjs +83 -31
  49. package/engine/index-records.mjs +63 -4
  50. package/engine/index.mjs +15 -0
  51. package/engine/infobox-registry.mjs +50 -3
  52. package/engine/infobox.mjs +12 -8
  53. package/engine/item-compiler.mjs +10 -10
  54. package/engine/journals.mjs +3 -0
  55. package/engine/macros.mjs +16 -13
  56. package/engine/map-notes.mjs +29 -22
  57. package/engine/metadata-index.mjs +44 -36
  58. package/engine/note-vocabulary.mjs +71 -29
  59. package/engine/pack-router.mjs +14 -0
  60. package/engine/packagebuild-index.mjs +124 -0
  61. package/engine/packages.mjs +83 -0
  62. package/engine/pathnames.mjs +74 -0
  63. package/engine/pdf-build.mjs +133 -8
  64. package/engine/pdf-render.mjs +49 -12
  65. package/engine/scenes.mjs +12 -9
  66. package/engine/site-build.mjs +43 -16
  67. package/engine/site-index.mjs +10 -1
  68. package/engine/subtype-registry.mjs +21 -0
  69. package/engine/web-wikilinks.mjs +46 -12
  70. package/engine/wikilink-syntax.mjs +20 -2
  71. package/engine/wikilinks.mjs +15 -2
  72. package/hm3/actors.mjs +11 -38
  73. package/manifest.mjs +67 -13
  74. package/package.json +5 -2
  75. package/packagebuild-metadata.jsonl +13 -0
  76. package/sohl/actors.mjs +12 -86
  77. package/sohl/note-schemas.mjs +4 -16
  78. package/types/content-config.d.mts +8 -0
  79. package/types/engine/actor-compiler.d.mts +29 -0
  80. package/types/engine/art-fields.d.mts +192 -0
  81. package/types/engine/asset-index.d.mts +92 -0
  82. package/types/engine/asset-types.d.mts +110 -0
  83. package/types/engine/base-compiler.d.mts +42 -1
  84. package/types/engine/compile-corpus.d.mts +4 -1
  85. package/types/engine/content-charset.d.mts +4 -0
  86. package/types/engine/content-embeds.d.mts +218 -0
  87. package/types/engine/content-html.d.mts +4 -0
  88. package/types/engine/content-icons.d.mts +4 -0
  89. package/types/engine/content-images.d.mts +15 -2
  90. package/types/engine/content-index.d.mts +27 -15
  91. package/types/engine/dependency-bump.d.mts +2 -2
  92. package/types/engine/frontmatter-lint.d.mts +11 -14
  93. package/types/engine/helpers.d.mts +7 -2
  94. package/types/engine/index-records.d.mts +44 -3
  95. package/types/engine/index.d.mts +5 -0
  96. package/types/engine/infobox-registry.d.mts +36 -1
  97. package/types/engine/infobox.d.mts +6 -4
  98. package/types/engine/macros.d.mts +9 -5
  99. package/types/engine/map-notes.d.mts +10 -6
  100. package/types/engine/metadata-index.d.mts +2 -17
  101. package/types/engine/note-vocabulary.d.mts +30 -0
  102. package/types/engine/packagebuild-index.d.mts +56 -0
  103. package/types/engine/packages.d.mts +62 -0
  104. package/types/engine/pathnames.d.mts +41 -81
  105. package/types/engine/pdf-build.d.mts +58 -1
  106. package/types/engine/pdf-render.d.mts +3 -1
  107. package/types/engine/scenes.d.mts +2 -1
  108. package/types/engine/site-build.d.mts +5 -1
  109. package/types/engine/site-index.d.mts +4 -1
  110. package/types/engine/subtype-registry.d.mts +20 -0
  111. package/types/engine/web-wikilinks.d.mts +14 -4
  112. package/types/engine/wikilink-syntax.d.mts +13 -1
  113. package/types/engine/wikilinks.d.mts +7 -1
  114. package/types/manifest.d.mts +42 -1
  115. package/types/sohl/actors.d.mts +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,250 @@
1
1
  # @heroiclands/package-build
2
2
 
3
+ ## 22.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - a278438: **A manifest's `url` is the package's homepage.** It is the Project Homepage link
8
+ a reader follows from the Foundry package listing _before_ installing anything,
9
+ so it answers "what is this?" — which the authored page at
10
+ `https://www.heroiclands.org/<contentPackage>/` does and a source tree does not.
11
+ `bugs`, `manifest` and `download` address release artefacts and stay on the
12
+ repository holding them. The address is derived from the content package rather
13
+ than declared, because the shared site-deploy workflow already publishes there; a
14
+ declared copy would be a second spelling of a settled fact, and the one free to
15
+ drift, since nothing fetches `url` the way Foundry fetches `manifest`.
16
+
17
+ **Breaking — `releaseUrls` takes `homeUrl`.** A call without it produced a
18
+ manifest advertising `undefined`, so the parameter is required rather than
19
+ defaulted. `packageHomepage` and `HOMEPAGE_ORIGIN` are exported beside it, and
20
+ `packageHomepage` refuses an empty name for the same reason.
21
+
22
+ **A configuration always names a content package**, so the manifest no longer
23
+ carries the branch that handled one that did not: the content index is advertised
24
+ unconditionally, which is what the comment above it already claimed.
25
+
26
+ ### Patch Changes
27
+
28
+ - dec6ef4: **A full-page picture prints where it was written** — In the book, an image
29
+ marked as full width now opens the page that follows the prose introducing it,
30
+ with the rest of that prose running below it. It can no longer appear above the
31
+ sentence that points at it, or a page later than the text that follows it.
32
+
33
+ - _A picture that asks for a float still floats_, which is what a float is for.
34
+ - _A picture taller than the page takes a page of its own._
35
+ - 32322bd: **Dependency bumps** — `package-build bump` is described by what it is for: npm
36
+ performs the resolution, so a version whose dependency set differs from the one
37
+ it replaces is taken as correctly as one that moves three lines, while patching
38
+ the lockfile by hand is right only while the two dependency sets match. npm
39
+ writes `package-lock.json` with the indentation `package.json` uses, so a
40
+ formatted manifest yields a formatted lockfile; the bump holds each file to the
41
+ indent it already carries, which is what covers a lockfile indented unlike its
42
+ manifest.
43
+
44
+ ## 21.2.0
45
+
46
+ ### Minor Changes
47
+
48
+ - 9ccd9e1: **Art and sound have addresses** — A package's pictures and sound clips are now
49
+ addressed the way its notes are. `icon`, `image` and `audio` are types a
50
+ reference can reach, one per tree: `assets/icons`, `assets/images` and
51
+ `assets/audio`. The filename is the name — `anvil.svg` is `icon-anvil` — and the
52
+ directories above it are the package's own business, so a tree can be tidied
53
+ into whatever arrangement suits the people who maintain it without a single
54
+ reference changing.
55
+
56
+ - _The extension stays out of the name._ Changing a picture from SVG to WebP is
57
+ dropping a different file in place; nothing that names it has to be touched.
58
+ - _Two files cannot claim one name._ A root's names are one list however deeply
59
+ it nests, and the build says which two files collided.
60
+ - _Attribution travels with the file._ Who made it, where it came from and what
61
+ licence it carries are published beside it, taken from the `provenance.yaml`
62
+ nearest the file or from a record written for that one file alone.
63
+ - _A package can lend its art._ Every address says which package holds the
64
+ bytes, so a picture one package ships resolves for another that cites it — on
65
+ the website, in the book, and in Foundry.
66
+ - `packagebuild` is a reserved name, held for the files the toolchain itself
67
+ ships, so no package may claim it.
68
+
69
+ Fonts are deliberately not addressable: nobody names a typeface the way they
70
+ name a picture, and a stylesheet and a typesetter each want something an address
71
+ cannot give them.
72
+ - 888f64a: **An image a Foundry journal cannot serve is refused** — An image in a note's
73
+ body names the package that owns the file, and a journal can only draw one from
74
+ a package the install carries. An address naming a package the build declares no
75
+ relationship with — or `packagebuild`, whose shared banners travel with the
76
+ toolchain and belong to the website and the book — is reported with the file,
77
+ line and column it sits on, and the build stops rather than compiling a document
78
+ whose picture resolves against nothing.
79
+
80
+ - _Both spellings, one answer._ `![alt](…)` and `![[address|label]]` are one
81
+ image, so an address is refused in the same words whichever way it is written.
82
+ - _`banner:` is where a shared banner belongs._ It reaches the page and the
83
+ book's section plates and no compiled document, so a note plating a section
84
+ with one of the toolchain's banners is doing the right thing.
85
+ - _An address naming no package still passes through._ A URL, a
86
+ protocol-relative `//host/…`, a `data:` URI and a `/`-rooted path reach a
87
+ journal untouched, which is how a note draws core Foundry art or art from a
88
+ package outside this constellation.
89
+ - b34686f: **The shared banners can be named from anywhere** — A note borrows one of the
90
+ section banners the toolchain ships by naming it, and nothing has to be declared
91
+ or downloaded first:
92
+
93
+ ```yaml
94
+ data:
95
+ banner: packagebuild-none-image-skillbnr
96
+ ```
97
+
98
+ The pictures travel with the toolchain itself, so a package plates a section
99
+ without keeping its own copy and without taking on a dependency on some parent
100
+ system it has no other relationship with. They appear on the website and in the
101
+ book; Foundry installs nothing for them, which is why nothing in a compendium
102
+ ever names one.
103
+
104
+ `packagebuild` is reserved, so no package can claim the name out from under
105
+ them.
106
+ - 9a937e7: **A note names its art, and the art arrives** — The picture a document carries
107
+ is chosen by name now, the way everything else in a note is. `icon` is what a
108
+ directory listing shows beside the name, `tokenIcon` what a token on the canvas
109
+ wears, `bgImage` a map's background, and `banner` the hero image at the top of a
110
+ page. Write the name of the file and the build finds it.
111
+
112
+ - _The art actually reaches the document._ Every compiled item took its type's
113
+ stock picture whatever its note said; it now carries the one it names, and the
114
+ same goes for a being's profile art, its token and its portrait.
115
+ - _A map is art all through._ Its background, the pictures on its tiles and the
116
+ sound clips placed around it are all named the same way and all resolved.
117
+ - _A being with no picture of its own gets one that suits it_ — a person and a
118
+ creature fall back to different art, chosen from what the note says it is.
119
+ - _A picture one package ships reaches another that names it_, on the website,
120
+ in the book and in Foundry, with each getting the address it serves.
121
+ - _`tokenIcon` unset follows `icon`._ A being naming one picture wears it on the
122
+ canvas too.
123
+ - _A name nothing answers is reported against the note_ rather than quietly
124
+ becoming the stock picture.
125
+
126
+ A being's portrait is the first image inside its `{#appearance}` section now,
127
+ written in the prose that describes it rather than declared in a field — where
128
+ an author can see it, move it and caption it like any other picture.
129
+ - 7661355: **A picture goes where it belongs in the prose** — `![[address|label]]` puts an
130
+ image where it is written, and every surface draws it there: a Foundry journal,
131
+ the website and the book alike. It is the wikilink already in use, with `!`
132
+ meaning _draw it here_ rather than _link to it_, so nothing new has to be
133
+ learned — the same short form, the same way of reaching another package's
134
+ artwork, the same complaint when an address names nothing.
135
+
136
+ - _The label is what the picture says._ It is the caption in print, and the
137
+ words a screen reader announces when the image does not load. `![[anvil|]]`
138
+ says the picture is decoration and needs none.
139
+ - _It sits where it is told._ An embed takes the same `{…}` an image does — a
140
+ width, a position, or both in either order — and an unrecognised value is
141
+ refused with the file and line it is on rather than quietly ignored.
142
+ - _Only a picture can be embedded._ Naming a character or a skill where a file
143
+ belongs is refused, and the message says to link to it instead.
144
+ - _A being's portrait opens its appearance._ Every creature and every character
145
+ now shows its picture at the top of what it looks like, in the compendium, on
146
+ the page and in the book.
147
+ - 84a6715: **Shared section banners** — package-build now ships the thirteen banner images
148
+ many packages draw on, and publishes them to consumers. A package can plate a
149
+ section without keeping its own copy, and without declaring a dependency on some
150
+ parent system or module to borrow one.
151
+
152
+ They are licensed CC-BY-SA-4.0, recorded beside them.
153
+ - 0c10ba5: **Everything a being carries now has a picture** — Gear and skills written out
154
+ inside a being's note, rather than copied from the catalogue, reached the sheet
155
+ with no artwork at all. They carry art now, by the same two rules everything
156
+ else does.
157
+
158
+ - _An item can name its own._ Write an icon under `data:` and the sheet shows it.
159
+ - _And it takes one when it names none._ A whetstone somebody wrote out by hand
160
+ gets the picture every other piece of miscellaneous gear gets, instead of a
161
+ blank.
162
+ - fc33f24: **The book sets in the faces the build carries, not the ones the machine has.**
163
+ Headings, running heads, table labels and captions are set in _Libertinus Sans_
164
+ — the toolchain ships it, so a book sets the same way on any machine, and the
165
+ sans no longer comes out in the body face because nothing could resolve it.
166
+ _Libertinus Mono_ is shipped beside it for a package that sets its code spans in
167
+ it; the default mono is unchanged.
168
+
169
+ **A face that resolves to nothing is reported.** A compile that cannot find a
170
+ family still writes a book, set in whatever the fallback reached — a wrong face
171
+ that nobody sees. The compiler's warnings are now findings like any other, with
172
+ the file, the line and the column.
173
+
174
+ ### Patch Changes
175
+
176
+ - d2d029a: **A system panel says what the module actually ships** — A page's SoHL or HM3
177
+ box reads _Not available_ only where that system really has no document for the
178
+ note, which is what a reader acts on.
179
+
180
+ - _A note need not name a system to have one._ Where the whole of a subject
181
+ lives in its own fields — an affiliation, a being written without system
182
+ detail — the panel now carries the subject's fields instead of claiming the
183
+ page is outside the system's reach.
184
+ - _A system the module ships nothing for still says so_, on every page that
185
+ could have carried it.
186
+ - 9d4ba48: **Content format** — A map names its art the way every other note does. Its
187
+ background is `bgImage`, an `image` address; a tile names its art with `image`
188
+ and an ambient sound names its clip with `audio`. A map carries no `img` — a
189
+ Scene has no such field.
190
+ - acea050: **Content format** — The specification describes art as addresses rather than
191
+ file paths. A note names its artwork with a wikilink address, an asset lives at
192
+ an address that holds exactly one file with the extension outside the name, and
193
+ `icon`, `image`, `font` and `audio` are types a link can reach like any other.
194
+
195
+ - The five art slots are `icon`, `portrait`, `tokenIcon`, `bgImage` and
196
+ `banner`, each a wikilink field with its own default type.
197
+ - An image in a note's body is written `![[address|alt text]]`, an empty label
198
+ marking it decorative.
199
+ - `packagebuild` is reserved, so any package can name a shared section banner
200
+ without declaring a dependency to reach it.
201
+
202
+ The build reads art as file paths, so it refuses a tree written to this
203
+ specification. The specification is the target; the build is what runs today.
204
+ - 60815eb: **A lint finding opens where it says it is** — Every path a content lint prints
205
+ is relative to the directory the command was run from, so one `content-build
206
+ lint` run reports every finding in the same shape and each one opens in an
207
+ editor, a CI annotation or a `$EDITOR +line` jump.
208
+
209
+ - _Characters, icons, raw HTML and image directives_ report the note's path the
210
+ way the address and frontmatter rules beside them already do.
211
+ - 7d79e70: **Content format** — A being's portrait is a picture in its prose, not a field.
212
+ It opens the note's `{#appearance}` section — the **lead image** — and
213
+ `data.portrait` is gone:
214
+
215
+ ```markdown
216
+ # Appearance {#appearance}
217
+
218
+ ![[branwldrgr|Brànwâal Dôrgaar]]{float: top-left}
219
+ ```
220
+
221
+ Nothing about that embed is special: it is an ordinary embedded image with an
222
+ ordinary directive, and the strictness is the convention that the portrait opens
223
+ the section, so every being note reads the same way. The section matters as well
224
+ as the order — `{#appearance}` is what becomes an actor's appearance, so a
225
+ picture above that heading reaches no document. An author can move it, caption it
226
+ or drop it like any other picture.
227
+
228
+ Four art slots remain — `icon`, `tokenIcon`, `bgImage` and `banner` — each
229
+ naming art that a document field needs. An embed also takes the same `{…}`
230
+ directive an image does, so a float or a width applies to either.
231
+ - d6d837c: **Content format** — An asset's address is derived from where its file sits.
232
+ Three roots, one per type — `assets/icons`, `assets/images` and `assets/audio` —
233
+ and any file with a matching extension anywhere beneath one is an asset of that
234
+ type, however deep. The filename is the shortcode, the
235
+ extension is not part of the address, and the directories in between are the
236
+ package's own business.
237
+
238
+ A root's shortcodes are one flat namespace, so two files under one root sharing
239
+ a basename are a build error naming both. Across roots they are different
240
+ addresses: `icon-anvil` and `image-anvil` name different pictures for different
241
+ purposes.
242
+
243
+ A font is not an asset and has no address. Nothing names a typeface the way a
244
+ note names a picture, and neither consumer of a font could use an address
245
+ anyway: a stylesheet wants a relative `url()` and the book wants a family name.
246
+ Fonts stay ordinary files a package ships and points a tool at.
247
+
3
248
  ## 21.1.0
4
249
 
5
250
  ### Minor 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
@@ -2538,11 +2609,11 @@ pdf:
2538
2609
  out: build/dist # default
2539
2610
  front: # prose before the contents
2540
2611
  - prose/colophon.md
2541
- fonts:
2612
+ fonts: # every key optional — the defaults below
2542
2613
  serif: Libertinus Serif
2543
2614
  sans: Libertinus Sans
2544
2615
  mono: DejaVu Sans Mono
2545
- 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
2546
2617
  iconFonts: # icon family → the font carrying its glyphs
2547
2618
  fontawesome: assets/fonts/fa-solid-900.ttf
2548
2619
  binary: typst # when it is not simply `typst` on PATH
@@ -2551,6 +2622,39 @@ pdf:
2551
2622
  Nothing here is an address or a brand: the title, the front matter and the faces
2552
2623
  are the publishing repository's to choose, which is why they are configuration.
2553
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
+
2554
2658
  ### Typst is a binary, not a dependency
2555
2659
 
2556
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
@@ -1137,10 +1137,11 @@ function e2eCommand() {
1137
1137
  * `bump [packages..]` — take a newer version of a dependency.
1138
1138
  *
1139
1139
  * npm does the resolving, so a bump whose dependency set changed is as correct
1140
- * as one that moves three lines. What this adds is the indentation: every
1141
- * repository here writes `package-lock.json` with four spaces and
1142
- * prettier-ignores it, and npm rewrites it with two, so the version change
1143
- * arrives buried in a whole-file reformat.
1140
+ * as one that moves three lines; patching the lockfile by hand is right only
1141
+ * while the two dependency sets match, and nothing says when they stop
1142
+ * matching. npm writes the lockfile with `package.json`'s indentation, and
1143
+ * this holds each file to the indent it already carried, so a lockfile indented
1144
+ * unlike its manifest keeps its own.
1144
1145
  *
1145
1146
  * Named nothing, it takes the first-party packages — the ones a person bumps
1146
1147
  * by hand, the moment a release publishes, usually to unblock the change that
@@ -1151,7 +1152,7 @@ function e2eCommand() {
1151
1152
  function bumpCommand() {
1152
1153
  return {
1153
1154
  command: "bump [packages..]",
1154
- describe: "Take a newer version of a dependency, keeping the lockfile's formatting",
1155
+ describe: "Take a newer published version of a declared dependency",
1155
1156
  builder: (y) =>
1156
1157
  y
1157
1158
  .positional("packages", {