@heroiclands/package-build 23.13.0 → 24.0.1

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 (236) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +2 -1
  3. package/assets/preview/gitea.ini +12 -7
  4. package/assets/styles/content-base.css +150 -1
  5. package/bin/content-commands.mjs +356 -210
  6. package/bin/package-build.mjs +3 -2
  7. package/ci/check-banners.mjs +7 -7
  8. package/config.mjs +21 -6
  9. package/content-config.mjs +199 -80
  10. package/docs/api.md +93 -72
  11. package/docs/authoring/links-and-markup.md +316 -78
  12. package/docs/commands.md +248 -80
  13. package/docs/configuration.md +210 -102
  14. package/docs/content-format.md +2 -2
  15. package/docs/diagnostics.md +2 -2
  16. package/docs/getting-started.md +1 -1
  17. package/docs/guides/icons.md +1 -1
  18. package/docs/guides/module-project.md +5 -8
  19. package/docs/guides/release-and-deploy.md +2 -2
  20. package/docs/guides/site.md +155 -23
  21. package/docs/guides/system-project.md +1 -1
  22. package/docs/guides/writing-in-invented-scripts.md +1247 -0
  23. package/docs/index.md +1 -0
  24. package/docs/project-setup.md +28 -30
  25. package/docs/reference/format-details.md +589 -308
  26. package/docs/reference/note-types.md +40 -10
  27. package/docs/reference/theme-pages.md +127 -108
  28. package/docs/source-preview.md +15 -1
  29. package/engine/asset-shipping.mjs +22 -10
  30. package/engine/base-compiler.mjs +62 -104
  31. package/engine/changelog-lint.mjs +1 -1
  32. package/engine/content-address.mjs +1 -1
  33. package/engine/content-alerts.mjs +8 -4
  34. package/engine/content-blocks.mjs +26 -11
  35. package/engine/content-embeds.mjs +1 -1
  36. package/engine/content-expand.mjs +376 -0
  37. package/engine/content-figures.mjs +13 -6
  38. package/engine/content-format.yaml +8 -0
  39. package/engine/content-glyphs.mjs +213 -0
  40. package/engine/content-images.mjs +6 -7
  41. package/engine/content-links.mjs +3 -3
  42. package/engine/content-lint.mjs +1 -1
  43. package/engine/content-render.mjs +453 -0
  44. package/engine/content-scripts.mjs +326 -27
  45. package/engine/content-spans.mjs +4 -1
  46. package/engine/content-styles.mjs +91 -0
  47. package/engine/content-symbols.mjs +186 -0
  48. package/engine/content-verse.mjs +6 -18
  49. package/engine/core-report.mjs +169 -0
  50. package/engine/core-vocabulary.mjs +208 -0
  51. package/engine/dictionary-html.mjs +119 -0
  52. package/engine/field-reference.mjs +1 -1
  53. package/engine/frontmatter-lint.mjs +1 -1
  54. package/engine/heading-attributes.mjs +89 -0
  55. package/engine/helpers.mjs +61 -101
  56. package/engine/homepage.mjs +17 -29
  57. package/engine/html-minify.mjs +70 -0
  58. package/engine/index.mjs +8 -5
  59. package/engine/language-rows.mjs +8 -2
  60. package/engine/language-terms.mjs +115 -14
  61. package/engine/language-words.mjs +12 -0
  62. package/engine/logographic.mjs +255 -0
  63. package/engine/map-lexicon.mjs +221 -25
  64. package/engine/map-places.mjs +5 -4
  65. package/engine/markdown-expressions.mjs +0 -2
  66. package/engine/markdownlint-run.mjs +9 -3
  67. package/engine/markup-validation.mjs +21 -0
  68. package/engine/metre-declaration.mjs +134 -0
  69. package/engine/note-matter.mjs +2 -2
  70. package/engine/note-vocabulary.mjs +187 -3
  71. package/engine/pdf-build.mjs +68 -133
  72. package/engine/pdf-render.mjs +102 -44
  73. package/engine/post-fields.mjs +157 -0
  74. package/engine/preview-index.mjs +130 -0
  75. package/engine/preview-source.mjs +450 -0
  76. package/engine/project-init.mjs +5 -12
  77. package/engine/prose-config.mjs +3 -3
  78. package/engine/run-words.mjs +3 -2
  79. package/engine/script-emphasis-terms.mjs +38 -0
  80. package/engine/script-emphasis.mjs +295 -0
  81. package/engine/script-font-delivery.mjs +4 -4
  82. package/engine/site-build.mjs +265 -313
  83. package/engine/site-config.mjs +26 -238
  84. package/engine/site-files.mjs +175 -0
  85. package/engine/site-index.mjs +9 -4
  86. package/engine/site-preview.mjs +50 -523
  87. package/engine/site-reach.mjs +213 -0
  88. package/engine/site-render.mjs +668 -0
  89. package/engine/site-root.mjs +90 -39
  90. package/engine/site-search.mjs +161 -0
  91. package/engine/site-serve.mjs +274 -0
  92. package/engine/site-theme-banner.mjs +154 -0
  93. package/engine/site-theme-urls.mjs +125 -0
  94. package/engine/site-theme.mjs +939 -0
  95. package/engine/sql-tables.mjs +9 -6
  96. package/engine/text-maps.mjs +57 -10
  97. package/engine/typographer.mjs +248 -0
  98. package/engine/verse-metre.mjs +357 -0
  99. package/engine/wikilink-syntax.mjs +29 -47
  100. package/engine/wikilinks.mjs +758 -279
  101. package/engine/word-forms.mjs +39 -24
  102. package/engine/word-rows.mjs +12 -2
  103. package/engine/word-terms.mjs +29 -4
  104. package/manifest.mjs +3 -4
  105. package/package.json +10 -7
  106. package/{hugo-theme → site-theme}/data/banners.yaml +6 -10
  107. package/site-theme/layouts/base.hbs +31 -0
  108. package/site-theme/layouts/blog-list.hbs +30 -0
  109. package/site-theme/layouts/blog-post.hbs +40 -0
  110. package/site-theme/layouts/home.hbs +35 -0
  111. package/site-theme/layouts/list.hbs +20 -0
  112. package/site-theme/layouts/not-found.hbs +31 -0
  113. package/site-theme/layouts/page.hbs +7 -0
  114. package/site-theme/partials/copy-buttons.hbs +37 -0
  115. package/site-theme/partials/draft-notice.hbs +5 -0
  116. package/site-theme/partials/exturl.hbs +2 -0
  117. package/{hugo-theme/layouts/partials/footer.html → site-theme/partials/footer.hbs} +10 -7
  118. package/site-theme/partials/header.hbs +44 -0
  119. package/site-theme/partials/hero-banner.hbs +11 -0
  120. package/site-theme/partials/infobox-entry.hbs +2 -0
  121. package/site-theme/partials/infobox-section.hbs +31 -0
  122. package/site-theme/partials/infobox-value.hbs +2 -0
  123. package/site-theme/partials/infobox.hbs +18 -0
  124. package/site-theme/partials/list-members.hbs +9 -0
  125. package/site-theme/partials/nav-links.hbs +5 -0
  126. package/site-theme/partials/page-body.hbs +48 -0
  127. package/site-theme/partials/page-list.hbs +14 -0
  128. package/site-theme/partials/related.hbs +24 -0
  129. package/site-theme/partials/search-meta.hbs +6 -0
  130. package/site-theme/partials/search-names.hbs +2 -0
  131. package/site-theme/partials/search.hbs +52 -0
  132. package/site-theme/partials/tags.hbs +4 -0
  133. package/site-theme/partials/toc.hbs +7 -0
  134. package/{hugo-theme → site-theme}/static/css/style.css +14 -0
  135. package/stage.mjs +1 -2
  136. package/types/config.d.mts +8 -4
  137. package/types/content-config.d.mts +15 -15
  138. package/types/engine/asset-shipping.d.mts +5 -2
  139. package/types/engine/base-compiler.d.mts +20 -2
  140. package/types/engine/content-address.d.mts +1 -1
  141. package/types/engine/content-alerts.d.mts +8 -2
  142. package/types/engine/content-blocks.d.mts +11 -4
  143. package/types/engine/content-expand.d.mts +288 -0
  144. package/types/engine/content-figures.d.mts +11 -3
  145. package/types/engine/content-glyphs.d.mts +85 -0
  146. package/types/engine/content-images.d.mts +6 -7
  147. package/types/engine/content-links.d.mts +1 -1
  148. package/types/engine/content-render.d.mts +199 -0
  149. package/types/engine/content-scripts.d.mts +62 -0
  150. package/types/engine/content-spans.d.mts +1 -1
  151. package/types/engine/content-styles.d.mts +33 -0
  152. package/types/engine/content-symbols.d.mts +35 -0
  153. package/types/engine/core-report.d.mts +45 -0
  154. package/types/engine/core-vocabulary.d.mts +53 -0
  155. package/types/engine/dictionary-html.d.mts +8 -0
  156. package/types/engine/field-reference.d.mts +1 -1
  157. package/types/engine/heading-attributes.d.mts +20 -0
  158. package/types/engine/helpers.d.mts +3 -10
  159. package/types/engine/homepage.d.mts +11 -24
  160. package/types/engine/html-minify.d.mts +9 -0
  161. package/types/engine/index.d.mts +2 -1
  162. package/types/engine/language-terms.d.mts +24 -2
  163. package/types/engine/logographic.d.mts +45 -0
  164. package/types/engine/map-lexicon.d.mts +48 -8
  165. package/types/engine/map-places.d.mts +8 -0
  166. package/types/engine/markdown-expressions.d.mts +0 -2
  167. package/types/engine/metre-declaration.d.mts +39 -0
  168. package/types/engine/pdf-render.d.mts +6 -2
  169. package/types/engine/post-fields.d.mts +44 -0
  170. package/types/engine/preview-index.d.mts +72 -0
  171. package/types/engine/preview-source.d.mts +51 -0
  172. package/types/engine/script-emphasis-terms.d.mts +21 -0
  173. package/types/engine/script-emphasis.d.mts +84 -0
  174. package/types/engine/script-font-delivery.d.mts +4 -4
  175. package/types/engine/site-build.d.mts +71 -113
  176. package/types/engine/site-config.d.mts +14 -134
  177. package/types/engine/site-files.d.mts +73 -0
  178. package/types/engine/site-index.d.mts +11 -3
  179. package/types/engine/site-preview.d.mts +15 -19
  180. package/types/engine/site-reach.d.mts +76 -0
  181. package/types/engine/site-render.d.mts +173 -0
  182. package/types/engine/site-root.d.mts +14 -4
  183. package/types/engine/site-search.d.mts +54 -0
  184. package/types/engine/site-serve.d.mts +44 -0
  185. package/types/engine/site-theme-banner.d.mts +51 -0
  186. package/types/engine/site-theme-urls.d.mts +60 -0
  187. package/types/engine/site-theme.d.mts +127 -0
  188. package/types/engine/text-maps.d.mts +17 -3
  189. package/types/engine/typographer.d.mts +11 -0
  190. package/types/engine/verse-metre.d.mts +131 -0
  191. package/types/engine/wikilink-syntax.d.mts +30 -48
  192. package/types/engine/wikilinks.d.mts +330 -14
  193. package/types/engine/word-forms.d.mts +3 -2
  194. package/types/manifest.d.mts +3 -4
  195. package/types/stage.d.mts +1 -2
  196. package/types/vendor/markdownlint.d.mts +8 -0
  197. package/vendor/markdownlint.mjs +20388 -0
  198. package/engine/web-wikilinks.mjs +0 -594
  199. package/hugo-theme/layouts/404.html +0 -85
  200. package/hugo-theme/layouts/_default/baseof.html +0 -67
  201. package/hugo-theme/layouts/_default/list.html +0 -139
  202. package/hugo-theme/layouts/_default/single.html +0 -4
  203. package/hugo-theme/layouts/blog/list.html +0 -54
  204. package/hugo-theme/layouts/blog-post/single.html +0 -36
  205. package/hugo-theme/layouts/index.html +0 -75
  206. package/hugo-theme/layouts/partials/banner-url.html +0 -141
  207. package/hugo-theme/layouts/partials/cdn-url.html +0 -36
  208. package/hugo-theme/layouts/partials/dictionary-lists.html +0 -58
  209. package/hugo-theme/layouts/partials/draft-notice.html +0 -41
  210. package/hugo-theme/layouts/partials/draft-state.html +0 -26
  211. package/hugo-theme/layouts/partials/header.html +0 -35
  212. package/hugo-theme/layouts/partials/hero-banner.html +0 -85
  213. package/hugo-theme/layouts/partials/infobox/entry.html +0 -18
  214. package/hugo-theme/layouts/partials/infobox/items.html +0 -26
  215. package/hugo-theme/layouts/partials/infobox/section.html +0 -56
  216. package/hugo-theme/layouts/partials/infobox/value.html +0 -43
  217. package/hugo-theme/layouts/partials/infobox.html +0 -57
  218. package/hugo-theme/layouts/partials/page-body.html +0 -152
  219. package/hugo-theme/layouts/partials/related.html +0 -138
  220. package/hugo-theme/layouts/partials/search.html +0 -84
  221. package/hugo-theme/layouts/partials/site-url.html +0 -32
  222. package/hugo-theme/layouts/partials/tags.html +0 -30
  223. package/hugo-theme/layouts/partials/toc.html +0 -28
  224. package/hugo-theme/layouts/partials/warn-missing-banner.html +0 -3
  225. package/hugo-theme/layouts/shortcodes/cartouche.html +0 -64
  226. package/hugo-theme/layouts/shortcodes/exturl.html +0 -12
  227. package/hugo-theme/layouts/shortcodes/glyph.html +0 -43
  228. package/hugo-theme/layouts/shortcodes/pagelist.html +0 -63
  229. package/hugo-theme/theme.toml +0 -11
  230. package/types/engine/web-wikilinks.d.mts +0 -107
  231. /package/{hugo-theme → site-theme}/data/banner-kinds.yaml +0 -0
  232. /package/{hugo-theme → site-theme}/static/css/sohl-icons.css +0 -0
  233. /package/{hugo-theme → site-theme}/static/fonts/game-icons-kb.woff2 +0 -0
  234. /package/{hugo-theme → site-theme}/static/img/banners/takheperu-hieroglyphs.svg +0 -0
  235. /package/{hugo-theme → site-theme}/static/img/cartouches/takheperu.svg +0 -0
  236. /package/{hugo-theme → site-theme}/static/js/inline-spoilers.js +0 -0
@@ -160,8 +160,8 @@ which applies before either loader form gets a chance to derive anything.
160
160
 
161
161
  #### `homepage`
162
162
 
163
- The address a package's site is served at — read by the generated Hugo
164
- configuration for `baseURL`, independently of the Foundry manifest's own
163
+ The address a package's site is served at — read by the site build for the
164
+ site's base URL, independently of the Foundry manifest's own
165
165
  `url`, which derives from `contentPackage` instead (see
166
166
  [`packageBuild.manifest`](#packagebuildmanifest)). `null` when the package
167
167
  declares none.
@@ -179,14 +179,18 @@ declares none.
179
179
  `homepage` is not itself checked against `contentPackage` by `defineConfig`.
180
180
  `checkHomepage` in `config.mjs` is the check: `homepage` is required
181
181
  unconditionally — every package publishes a site — and must be an absolute
182
- URL whose path ends `/<contentPackage>/`. `package-build site` makes it
183
- before the generated `baseURL` is written, so a missing or mismatched
182
+ URL whose path ends `/<contentPackage>/` — or, for a site that states
183
+ [`site.base`](#site), whose path is that base, so a site served at `/` has
184
+ the root of its origin as its `homepage`. `package-build site build` makes
185
+ it before the site's settings are composed, so a missing or mismatched
184
186
  `homepage` is a finding on every site build:
185
187
 
186
188
  > ``package-build config: `homepage` is not declared in `package.json`, and every package needs one to build its site's `baseURL` from. Add `https://www.heroiclands.org/<contentPackage>/`.``
187
189
 
188
190
  > ``package-build config: `homepage` is `https://www.heroiclands.org/harn-ensemble`, but `contentPackage` is `harnensemble` — a package's site is served at `https://www.heroiclands.org/harnensemble/`, so `package.json`'s `homepage` must end `/harnensemble/`.``
189
191
 
192
+ > ``package-build config: `homepage` is `https://www.heroiclands.org/heroiclands/`, but `site.base` is `/`, so `package.json`'s `homepage` must be the root of its origin.``
193
+
190
194
  #### `author`
191
195
 
192
196
  The package's byline: the first entry of [`authors`](#authors), in npm's
@@ -604,7 +608,7 @@ HeroicLands layout, resolved against `rootDir`:
604
608
  | `paths.unpack` | `build/tmp/packs` | Where `unpack` extracts JSON back to. |
605
609
  | `paths.foreignCache` | `build/cache/foreign` | Where a dependency declaring `itemCatalog: true` or `assetArchive: true` is unpacked. |
606
610
  | `paths.metadataCache` | `build/cache/metadata` | Where a published content index is fetched to, for every declared dependency and every relationship declaring `itemCatalog: true`. |
607
- | `paths.navigationCache` | `build/cache/navigation` | Where the site navigation heroiclands.org publishes is fetched to, for the generated Hugo menu. |
611
+ | `paths.navigationCache` | `build/cache/navigation` | Where the site navigation heroiclands.org publishes is fetched to, for the site's menu. |
608
612
 
609
613
  Every configured path must be **relative** — an absolute one would escape
610
614
  the repository the config anchors:
@@ -949,25 +953,29 @@ Any other key under `docs.itemFields` is refused:
949
953
 
950
954
  **Type:** object · **Optional** · every key defaults to nothing published:
951
955
 
952
- | Key | Type | Default |
953
- | ------------------ | -------- | -------------------------------------------- |
954
- | `site.base` | string | `""` |
955
- | `site.title` | string | `""`, required when no manifest title exists |
956
- | `site.assets` | string | `""`, but required for `package-build site` |
957
- | `site.description` | string | `""`, but required for `package-build site` |
958
- | `site.packages` | string[] | `[]` |
959
- | `site.pass` | string | `""` |
960
- | `site.passOptions` | object | `{}` |
961
- | `site.notfound` | object | `null` |
962
- | `site.hugo` | object | `{}` |
963
- | `site.search` | boolean | `true` |
964
- | `site.maps` | boolean | `true` |
956
+ | Key | Type | Default |
957
+ | ------------------- | -------- | -------------------------------------------- |
958
+ | `site.base` | string | `""` |
959
+ | `site.title` | string | `""`, required when no manifest title exists |
960
+ | `site.assets` | string | `""`, but required for `site build` |
961
+ | `site.description` | string | `""`, but required for `site build` |
962
+ | `site.packages` | string[] | `[]` |
963
+ | `site.pass` | string | `""` |
964
+ | `site.passOptions` | object | `{}` |
965
+ | `site.notfound` | object | `null` |
966
+ | `site.search` | boolean | `true` |
967
+ | `site.maps` | boolean | `true` |
968
+ | `site.sections` | object | `{}` |
969
+ | `site.feed` | string | `""` |
970
+ | `site.tags` | boolean | `false` |
971
+ | `site.sitemaps` | string[] | `[]`, and only at the root of an origin |
972
+ | `site.mergeIndexes` | string[] | `[]` |
965
973
 
966
974
  The authored content tree determines which pages reach the web. `site` is
967
975
  framing: which named pass bundle
968
976
  supplies the repository's own body rewrites, and the residue of the
969
- [generated Hugo configuration](#the-generated-hugo-configuration) that is
970
- genuinely this repository's own.
977
+ [site settings](#what-the-site-build-reads) that is genuinely this
978
+ repository's own.
971
979
 
972
980
  **A site is its homepage and its pages.** The `type: homepage` note is the
973
981
  package's front page at `/<contentPackage>/`, and every other note is one page
@@ -981,15 +989,13 @@ So a page of documentation is a note — `type: doc`, addressed by its
981
989
  shortcode, and `pack: none` where it compiles into no Foundry document — and
982
990
  there is no second mechanism for mounting a directory of markdown.
983
991
 
984
- Where the Hugo tree is written is not a choice. `package-build site` writes
985
- the whole Hugo source tree under `build/hugo/` — the generated `hugo.toml`,
986
- the content mount at `build/hugo/content/`, Hugo's own cache — as a sibling
987
- of the deployment root `build/site/`, so nothing Hugo reads lands in what is
988
- published.
992
+ Where the site is written is not a choice. `package-build site build`
993
+ renders it under the deployment root `build/site/`, at
994
+ `build/site/<contentPackage>/` (or under the path `site.base` states).
989
995
 
990
996
  > ``package-build config: `site` must be a mapping.``
991
997
 
992
- > ``package-build config: `site.<key>` is not a recognized option (expected one of: base, title, assets, description, packages, pass, passOptions, notfound, hugo, search, maps).``
998
+ > ``package-build config: `site.<key>` is not a recognized option (expected one of: base, title, assets, description, packages, pass, passOptions, notfound, search, maps, sections, feed, tags, sitemaps, mergeIndexes).``
993
999
 
994
1000
  `site.assets` is the host every package's imagery is served from, and it is
995
1001
  the one address in this file that is not this repository's own. A note names
@@ -1002,8 +1008,8 @@ Absolute, and the trailing slash is trimmed:
1002
1008
 
1003
1009
  > ``package-build config: `site.assets` must be an absolute `http://` or `https://` address — it is the host every package's imagery is served from, and a relative value resolves against whichever page happens to carry the image.``
1004
1010
 
1005
- `package-build site` refuses to generate a configuration with no
1006
- `site.assets` at all — there is no defensible default, because the theme
1011
+ `package-build site build` refuses a configuration with no `site.assets` at
1012
+ all — there is no defensible default, because the theme
1007
1013
  resolves every relative asset against it:
1008
1014
 
1009
1015
  > ``package-build config: `site.assets` is not declared, and a site build needs one — it is the host every package's imagery is served from, and the theme resolves every relative asset against it.``
@@ -1014,7 +1020,7 @@ host, at `<site.assets>/<contentPackage>/icons/<basename>` and
1014
1020
  bucket behind the CDN is served at `site.assets`, so an object's key is its
1015
1021
  path below this value.
1016
1022
 
1017
- The generated Hugo configuration carries the same host as
1023
+ The site settings carry the same host as
1018
1024
  `params.cdnBaseURL`, which the theme resolves a relative asset path against.
1019
1025
  The two are one value read by two readers: the toolchain emits it into a
1020
1026
  page, and the theme joins it onto anything the toolchain left relative.
@@ -1026,7 +1032,7 @@ absent.
1026
1032
  `site.description` is the site's `<meta name="description">` — one plain
1027
1033
  sentence, distinct from the Foundry package browser's pitch
1028
1034
  ([`packageBuild.manifest.descriptionHtml`](#packagebuildmanifest), which
1029
- allows HTML). Required for `package-build site`, the way its title is:
1035
+ allows HTML). Required for `package-build site build`, the way its title is:
1030
1036
 
1031
1037
  > ``package-build config: `site.description` is not declared, and the site's `<meta name="description">` reads from it.``
1032
1038
 
@@ -1047,8 +1053,8 @@ names a registry):
1047
1053
  `site.passOptions` has no further shape of its own — it is passed to the
1048
1054
  resolved `site.pass` bundle unchanged.
1049
1055
 
1050
- `site.notfound` is the wording of the "page not found" page, written into
1051
- the generated Hugo configuration as `params.notfound`. The theme renders
1056
+ `site.notfound` is the wording of the "page not found" page, carried in the
1057
+ site settings as `params.notfound`. The theme renders
1052
1058
  the page for every site; what a repository supplies is the tagline, the
1053
1059
  noun the body prose calls the site, and the routes back. `tagline` and
1054
1060
  `sitenoun` are required once the block is present — a block declaring only
@@ -1089,31 +1095,8 @@ site:
1089
1095
 
1090
1096
  > ``package-build config: `site.notfound.links[<index>].<key>` is not a recognized option (expected one of: title, url, text).``
1091
1097
 
1092
- `site.hugo` is a mapping deep-merged over the generated Hugo configuration,
1093
- last — the escape hatch for the one key nobody anticipated. A repository
1094
- whose homepage reproduces a notice whose bare URLs must stand unedited turns
1095
- Goldmark's autolinker off:
1096
-
1097
- ```yaml
1098
- site:
1099
- hugo:
1100
- markup:
1101
- goldmark:
1102
- extensions:
1103
- linkify: false
1104
- ```
1105
-
1106
- Objects merge; an array or a scalar replaces what the generator wrote. Every
1107
- key the generator writes is refused here, naming its source — see
1108
- [the generated Hugo configuration](#the-generated-hugo-configuration) — so
1109
- the block cannot grow into a second configuration file:
1110
-
1111
- > ``package-build config: `site.hugo` must be a mapping.``
1112
-
1113
- > ``package-build config: `site.hugo.baseURL` is derived from package.json `homepage` and must not be declared — it would be overwritten, and the two would disagree with nothing to say so.``
1114
-
1115
1098
  `site.search` is whether the rendered site carries a search index. On by
1116
- default: `package-build site-root` runs Pagefind over the rendered pages after
1099
+ default: `package-build site build` runs Pagefind over the rendered pages after
1117
1100
  it writes `_headers`, and the index lands beside them as
1118
1101
  `build/site/<contentPackage>/pagefind/`, served at `/<contentPackage>/pagefind/`
1119
1102
  with the rest of the site. The theme loads it relative to the site's base URL
@@ -1147,30 +1130,157 @@ site:
1147
1130
 
1148
1131
  > ``package-build config: `site.maps` must be a boolean.``
1149
1132
 
1150
- ### The generated Hugo configuration
1151
-
1152
- `package-build site` writes `build/hugo/hugo.toml` on every run. Every value
1153
- in it has one source, and that source is where it is edited:
1154
-
1155
- | Key | Derived from |
1156
- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
1157
- | `baseURL` | `package.json` `homepage`, checked by `checkHomepage` — an absolute URL ending `/<contentPackage>/` |
1158
- | `title` | `site.title` when declared, otherwise `packageBuild.manifest.title` |
1159
- | `locale` | the organisation's locale, `en-us`, in `engine/site-config.mjs` |
1160
- | `publishDir` | `contentPackage`, under the deployment root `build/site` — written relative to `build/hugo/`, so `../site/<contentPackage>` |
1161
- | `contentDir` | the fixed content mount, `build/hugo/content` — written as `content` |
1162
- | `themesDir` | this package's own root, which holds the theme it ships, written relative to `build/hugo/` |
1163
- | `theme` | the theme's directory inside this package, `hugo-theme` |
1164
- | `disableKinds` | the toolchain, which renders a site as its homepage and its pages: `["section", "taxonomy", "term", "RSS"]` on every site, whatever its notes carry |
1165
- | `taxonomies` | the toolchain — never written, because `taxonomy` and `term` are disabled kinds |
1166
- | `outputs` | the toolchain — never written, because every listing kind is disabled |
1167
- | `params.description` | `site.description`, which is required |
1168
- | `params.author` | the first entry of `authors`, its `name`; absent when `authors` is empty |
1169
- | `params.cdnBaseURL` | `site.assets`, which is required |
1170
- | `params.brand` | the organisation's brand links — `logo`, `licenseURL`, `discordURL` — in `engine/site-config.mjs` |
1171
- | `params.notfound` | `site.notfound`; absent when undeclared |
1172
- | `markup.goldmark.renderer.unsafe` | the toolchain, whose pages carry raw HTML — a `<figure>` for every image, a `<span>` marking an unresolved link |
1173
- | `menu` | the navigation `package-build deps fetch` caches from `https://www.heroiclands.org/nav.json`, entry for entry, a dropdown's entries as `parent` entries |
1133
+ #### Where a site is served, and what it lists
1134
+
1135
+ `site.base` is the path the site is served at. Unset, a package's site is
1136
+ served at `/<contentPackage>/`; a value begins and ends with `/`, and `/`
1137
+ serves the site at the root of its origin, as heroiclands.org's own site is.
1138
+ `package.json`'s `homepage` is then that path on the origin (see
1139
+ [`homepage`](#homepage)), and `package-build site build` writes the site at
1140
+ that path under the deployed root — at `build/site/` itself for `/`:
1141
+
1142
+ > ``package-build config: `site.base` is `blog/`; it is the path the site is served at, which begins and ends with `/` — `/` for the root of the origin.``
1143
+
1144
+ `site.sections` publishes a note as a section's page. Each key is a section's
1145
+ name, published at `/<name>/`, and each value is the address of the note that
1146
+ is its page, written `<type>-<shortcode>`. The note keeps its title, its
1147
+ description and its body, and is published at the section rather than at its
1148
+ own address, so every link to it reaches `/<name>/`. A section's page lists
1149
+ the pages of its section that its body does not already link.
1150
+
1151
+ ```yaml
1152
+ site:
1153
+ sections:
1154
+ blog: doc-blog
1155
+ projects: doc-projects
1156
+ ```
1157
+
1158
+ A name is one address segment, and no section claims a path the site writes
1159
+ itself — `tags`, `css`, `js`, `fonts`, `img` or `pagefind`. A value is a note's
1160
+ address, never the homepage's, and no note is the page of two sections. A
1161
+ section whose note is missing from the content tree fails the build, located
1162
+ at its value:
1163
+
1164
+ > ``package-build config: `site.sections` must be a mapping of a section's name to the address of the note that is its page.``
1165
+
1166
+ > ``package-build config: `site.sections.the-blog` names the section `the-blog`, which is published at `/the-blog/` and so is one address segment: lowercase letters and digits.``
1167
+
1168
+ > ``package-build config: `site.sections.tags` names the section `tags`, a path the site writes itself (tags, css, js, fonts, img, pagefind).``
1169
+
1170
+ > ``package-build config: `site.sections.blog` is `Blog`; it is the address of the note that is the section's page, written `<type>-<shortcode>`, such as `doc-blog`.``
1171
+
1172
+ > ``package-build config: `site.sections.blog` is `homepage-root`, and the homepage is the site's front page, not a section's.``
1173
+
1174
+ > ``package-build config: `site.sections.news` is `doc-blog`, which is already the page of `blog`.``
1175
+
1176
+ > `` `site.sections.projects` is `doc-plans`, and no note in the content tree has that address, so the section has no page to publish at `/projects/`. ``
1177
+
1178
+ `site.feed` names the section the site's posts are published in. A post is a
1179
+ `doc` of `subType: post` (see the
1180
+ [`doc` reference](reference/note-types.md#doc)); with `site.feed` set, every
1181
+ post is a page of that section, which lists them newest first by their
1182
+ `data.date`, and the section's posts are written as an Atom feed at
1183
+ `/<section>/atom.xml`, newest first, which every page links in its head. Each
1184
+ entry names the post's `data.author`, or the site's byline where the post
1185
+ names none. The section may be one `site.sections` gives a page; one it does
1186
+ not is titled by its name. Without `site.feed` a post is a page in no section,
1187
+ and the site has no feed:
1188
+
1189
+ ```yaml
1190
+ site:
1191
+ sections:
1192
+ blog: doc-blog
1193
+ feed: blog
1194
+ ```
1195
+
1196
+ > ``package-build config: `site.feed` names the section `blog/atom.xml`, which is published at `/blog/atom.xml/` and so is one address segment: lowercase letters and digits.``
1197
+
1198
+ `site.tags` writes a page for each tag the site's pages carry, at
1199
+ `/tags/<tag>/`, listing the pages that carry it, and an index of every tag
1200
+ with how many pages carry it at `/tags/`. A page's tags then link to their
1201
+ pages. Off by default, when a page's tags are shown and link nowhere:
1202
+
1203
+ > ``package-build config: `site.tags` must be a boolean.``
1204
+
1205
+ `site.sitemaps` names the package sites, by `contentPackage`, whose sitemaps
1206
+ the site's sitemap index lists. It belongs to a site served at the root of an
1207
+ origin: the build writes `sitemap-index.xml`, naming the site's own
1208
+ `sitemap.xml` and `/<package>/sitemap.xml` on the same origin for each one
1209
+ named, and `robots.txt`, naming the index and every sitemap in it. Every site
1210
+ writes its own `sitemap.xml` whether or not it states this key.
1211
+
1212
+ ```yaml
1213
+ site:
1214
+ base: /
1215
+ sitemaps: [sohl, hm3, thalorna, kethira, thalornaaltart, harnensemble, harnadventures]
1216
+ ```
1217
+
1218
+ `site.mergeIndexes` names the package sites, by `contentPackage`, whose search
1219
+ indexes the site's own search reads beside its own, so one search box finds
1220
+ the pages of every site named. Each is read from `/<package>/pagefind/` on the
1221
+ site's own origin, which is where that package's site publishes its index, so
1222
+ the merge resolves where the sites share an origin — at heroiclands.org,
1223
+ through its routing Worker — and not on a site served alone, such as by
1224
+ `site serve`. Name only a package site whose `site.search` is on; one that
1225
+ publishes no index leaves the search with an index it cannot load.
1226
+
1227
+ ```yaml
1228
+ site:
1229
+ mergeIndexes: [sohl, thalorna, kethira, harnensemble]
1230
+ ```
1231
+
1232
+ An entry of either list is a package's `contentPackage`, named once, and
1233
+ never the site's own:
1234
+
1235
+ > ``package-build config: `site.sitemaps` must be a list of package sites, each named by its `contentPackage`.``
1236
+
1237
+ > ``package-build config: `site.sitemaps[1]` is `harn-adventures`, which is not a package site: name one by its `contentPackage`, lowercase letters and digits.``
1238
+
1239
+ > ``package-build config: `site.mergeIndexes[2]` names `sohl` more than once.``
1240
+
1241
+ > ``package-build config: `site.sitemaps[0]` is `heroiclands`, this site's own package.``
1242
+
1243
+ Each is refused where it cannot mean anything — a sitemap index on a site not
1244
+ at the root of its origin, and a merged search on a site with no search:
1245
+
1246
+ > ``package-build config: `site.sitemaps` names the package sites a sitemap index lists, and a sitemap index and `robots.txt` belong at the root of an origin; this site is served at `/thalorna/`, so declare `site.base: /` or drop the key.``
1247
+
1248
+ > ``package-build config: `site.mergeIndexes` names the search indexes this site's search reads beside its own, and `site.search` is `false`, so there is no search to read them.``
1249
+
1250
+ heroiclands.org's own site states them all:
1251
+
1252
+ ```yaml
1253
+ contentPackage: heroiclands
1254
+ packageKind: documentation
1255
+ site:
1256
+ base: /
1257
+ sections:
1258
+ blog: doc-blog
1259
+ projects: doc-projects
1260
+ feed: blog
1261
+ tags: true
1262
+ sitemaps: [sohl, hm3, thalorna, kethira, thalornaaltart, harnensemble, harnadventures]
1263
+ mergeIndexes: [sohl, thalorna, kethira, harnensemble]
1264
+ ```
1265
+
1266
+ ### What the site build reads
1267
+
1268
+ `package-build site build` composes the site's settings from sources the
1269
+ repository already states, a few constants of the organisation, and the
1270
+ navigation `deps fetch` cached. Every value has one source, and that source is
1271
+ where it is edited:
1272
+
1273
+ | Setting | Derived from |
1274
+ | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
1275
+ | base URL | `package.json` `homepage`, checked by `checkHomepage` — an absolute URL ending `/<contentPackage>/` |
1276
+ | title | `site.title` when declared, otherwise `packageBuild.manifest.title` |
1277
+ | `params.description` | `site.description`, which is required |
1278
+ | `params.author` | the first entry of `authors`, its `name`; absent when `authors` is empty |
1279
+ | `params.cdnBaseURL` | `site.assets`, which is required |
1280
+ | `params.brand` | the organisation's brand links — `logo`, `licenseURL`, `discordURL` — in `engine/site-config.mjs` |
1281
+ | `params.notfound` | `site.notfound`; absent when undeclared |
1282
+ | `params.scriptFonts` | the installed script fonts' stylesheet, present only when the package delivers fonts |
1283
+ | menu | the navigation `package-build deps fetch` caches from `https://www.heroiclands.org/nav.json`, entry for entry, a dropdown's entries as its `children` |
1174
1284
 
1175
1285
  The site build reads the navigation from the cache only. A cold cache is an
1176
1286
  error naming the command that fills it:
@@ -1192,13 +1302,10 @@ build the same way:
1192
1302
 
1193
1303
  > ``package-build config: `site.assets` is not declared, and a site build needs one — it is the host every package's imagery is served from, and the theme resolves every relative asset against it.``
1194
1304
 
1195
- Nothing else is emitted. `home` and `page` are the only kinds a site
1196
- renders: the homepage is the mount's `_index.md`, every note is a page, and
1197
- `section`, `taxonomy`, `term` and `RSS` are disabled on every site — so no
1198
- `[taxonomies]` or `[outputs]` is written, Hugo's default taxonomy pair never
1199
- applies, and a note's `tags:` reach the page's front matter and nothing
1200
- else. A tag is a field a content table filters on, not a page of its own.
1201
- Every other key is `site.hugo`'s to add.
1305
+ Nothing else is configurable. A site is its homepage and its pages: the
1306
+ homepage is the package root and every note is a page. A tag is a field a
1307
+ content table filters on; a note's `tags:` reach its page and nothing else
1308
+ unless `site.tags` writes a page for each.
1202
1309
 
1203
1310
  ### `pdf`
1204
1311
 
@@ -1748,7 +1855,7 @@ end in a slash when set (a missing one would silently fuse the prefix to
1748
1855
  the first section) and must not begin with one (which would make the
1749
1856
  recorded address package-absolute):
1750
1857
 
1751
- The site build uses this prefix for its Hugo source mount. Published note
1858
+ The site build mounts the content tree at this prefix. Published note
1752
1859
  addresses and content-index paths stay relative to the package root; the
1753
1860
  manifest's package homepage also stays at that root. A page staged under
1754
1861
  `kb/` can therefore publish at `/<contentPackage>/<type>-<shortcode>/`.
@@ -1987,7 +2094,9 @@ names a layer or none at all, with no specificity contest and no
1987
2094
  `!important`. The term column, the gutter and the width at which the list
1988
2095
  stacks are custom properties — `--pb-deflist-term-width`,
1989
2096
  `--pb-deflist-gutter` and `--pb-deflist-row-gap` — so a package adjusts them
1990
- without copying the rule.
2097
+ without copying the rule. `--pb-rubric` is the red a rubric script's emphasis
2098
+ is set in, `light-dark(#9c281b, #e0705f)`; see
2099
+ [emphasis in a script](reference/theme-pages.md#emphasis-in-a-script).
1991
2100
 
1992
2101
  Declare `false` to decline it; nothing is staged and nothing is added to
1993
2102
  `styles`:
@@ -2254,16 +2363,15 @@ the source directory:
2254
2363
 
2255
2364
  ## Every forbidden key, in one place
2256
2365
 
2257
- | Key | Why |
2258
- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
2259
- | `rootDir` | Forbidden in a YAML configuration — always the file's own directory. |
2260
- | `foundryPackage` | Forbidden in a YAML configuration — always the adjacent `package.json` `name`. |
2261
- | `homepage` | Forbidden in a YAML configuration — always the adjacent `package.json`'s own `homepage`. |
2262
- | `author` | Refused as an unknown key — the byline is the first entry of [`authors`](#authors). |
2263
- | `packageBuild.manifest.authors` | Forbidden — derived from [`authors`](#authors), without each entry's `role`. |
2264
- | `stats.systemId` | Forbidden in every configuration — derived from `packageKind`, `requiresSystem` or a lone declared system. |
2265
- | `stats.systemVersion` | Forbidden in every configuration — derived from `package.json` (a system) or `systems:` / `relationships.systems` (a module). |
2266
- | `packageBuild.manifest.id`, `.version`, `.description`, `.url`, `.bugs`, `.manifest`, `.download`, `.compatibility`, `.relationships`, `.packs` | Forbidden — each is derived from `package.json` or the top level of `package-build.config.yaml`; see [`packageBuild.manifest`](#packagebuildmanifest). |
2267
- | `site.hugo.baseURL`, `.title`, `.locale`, `.publishDir`, `.contentDir`, `.themesDir`, `.theme`, `.disableKinds`, `.taxonomies`, `.outputs`, `.params.description`, `.params.author`, `.params.cdnBaseURL`, `.params.brand`, `.params.notfound`, `.markup.goldmark.renderer.unsafe`, `.menu` | Forbidden — each is written by the site build from a source it names; see [the generated Hugo configuration](#the-generated-hugo-configuration). |
2268
- | `publish.site` (any value) | Refused — publication follows the authored content tree. |
2269
- | `packs`, `itemBuilders`, `docs`, `compatibility`, `relationships`, `systems`, `requiresSystem`, `stats`, `foundryPackage` | Forbidden in a `documentation` package — each describes a Foundry package this kind is not; see the key's own section for its located refusal message. |
2366
+ | Key | Why |
2367
+ | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
2368
+ | `rootDir` | Forbidden in a YAML configuration — always the file's own directory. |
2369
+ | `foundryPackage` | Forbidden in a YAML configuration — always the adjacent `package.json` `name`. |
2370
+ | `homepage` | Forbidden in a YAML configuration — always the adjacent `package.json`'s own `homepage`. |
2371
+ | `author` | Refused as an unknown key — the byline is the first entry of [`authors`](#authors). |
2372
+ | `packageBuild.manifest.authors` | Forbidden — derived from [`authors`](#authors), without each entry's `role`. |
2373
+ | `stats.systemId` | Forbidden in every configuration — derived from `packageKind`, `requiresSystem` or a lone declared system. |
2374
+ | `stats.systemVersion` | Forbidden in every configuration — derived from `package.json` (a system) or `systems:` / `relationships.systems` (a module). |
2375
+ | `packageBuild.manifest.id`, `.version`, `.description`, `.url`, `.bugs`, `.manifest`, `.download`, `.compatibility`, `.relationships`, `.packs` | Forbidden — each is derived from `package.json` or the top level of `package-build.config.yaml`; see [`packageBuild.manifest`](#packagebuildmanifest). |
2376
+ | `publish.site` (any value) | Refused — publication follows the authored content tree. |
2377
+ | `packs`, `itemBuilders`, `docs`, `compatibility`, `relationships`, `systems`, `requiresSystem`, `stats`, `foundryPackage` | Forbidden in a `documentation` package — each describes a Foundry package this kind is not; see the key's own section for its located refusal message. |
@@ -31,7 +31,7 @@ Leading `:` captions describe the next supported block; `:@` captions also numbe
31
31
 
32
32
  A code fence with language `verse` keeps verse lines, stanza breaks and relative indentation. Its numbered caption uses the **Poem** label. Generic `:::` divs and `[inline spans]{.class}` accept attributes. See [verse](authoring/links-and-markup.md#verse), [fenced divs](authoring/links-and-markup.md#fenced-divs) and [inline spans](authoring/links-and-markup.md#inline-spans). `numstep=N` numbers every Nth line. `col1=` and `col2=` set the poem in at most two columns, each a `:`-joined stack of `language[/mapping[/font]]` entries, the first in the normal tone and the rest in grey; with columns, each blank-line group of `[text]{lang=…}` spans is one verse line, every entry sets the span in its language, and a `***` line breaks the stanza. See [verse in columns](authoring/links-and-markup.md#verse-in-columns).
33
33
 
34
- A span, a generic div or a verse fence marks its text's language with `lang=`, the font it is set in with `font=` and a mapping with `map=`, each optional, and the runs inside a div or a fence inherit its keys. `lang=` is a name the package declares in `languages` or a BCP 47 tag, and gives the language tag alone. `font=` is a face of the installed `@heroiclands/fonts`, named by its class without `hl-`, or `mono`, `serif` or `sans`. `map=` names a mapping note: a `doc` note whose `data.map` lists the fonts it is drawn in and rows that rewrite the text before it is set, a font's own rows first. With `lang=` naming a language whose configured `note` names its language note, a word whose entry states a `native` form for the map is written by it, and the rows spell every other word. Every word of such a run is a lexicon form, a word of a name the language note's own register lists under a tongue other than `translation`, or a form a plural row, the verb pattern or an affix stating `replaces` derives from a lexicon form, and any other word is an error at the word. A character a face does not draw, after the map, is an error at the character it came from. Text with a font, a map or a declared language is plain. Every marked construct is a row of the `runs` relation, every mapping row of the `maps` relation, and every native form of the `natives` relation. See [marking language, font and mapping](authoring/links-and-markup.md#marking-language-font-and-mapping).
34
+ A span, a generic div or a verse fence marks its text's language with `lang=`, the font it is set in with `font=` and a mapping with `map=`, each optional, and the runs inside a div or a fence inherit its keys. `lang=` is a name the package declares in `languages` or a BCP 47 tag, and gives the language tag alone. `font=` is a face of the installed `@heroiclands/fonts`, named by its class without `hl-`, or `mono`, `serif` or `sans`. `map=` names a mapping note: a `doc` note whose `data.map` lists the fonts it is drawn in and rows that rewrite the text before it is set, a font's own rows first. With `lang=` naming a language whose configured `note` names its language note, a word whose entry states a `native` form for the map is written by it, and the rows spell every other word. A map stating `logographic: true` spells no word by its rows: each word is written by its own `native` entry or its parts' writings, and a word with neither, or whose form stands for entries written differently, is a located error. Every word of such a run is a lexicon form, a word of a name the language note's own register lists under a tongue other than `translation`, or a form a plural row, the verb pattern or an affix stating `replaces` derives from a lexicon form, and any other word is an error at the word. A character a face does not draw, after the map, is an error at the character it came from. A verse fence that states `scan=` (the `name` of a `data.metres` entry of a `doc` note) with a `lang=` whose language note states `data.sounds.stress` is counted line by line by the beat convention, and a line that cannot have the metre's beats is a warning at the line; see [metres](reference/format-details.md#metres). Text with a font, a map or a declared language is plain, except that text set in a face takes `*…*` and `**…**`: they render by the convention its language note's `data.emphasis` states, else the one the script note listing its face states in `data.script` (`rubric` or `overline`), else plainly, and a language whose `data.emphasis` is `words` makes them an error. Every marked construct is a row of the `runs` relation, every mapping row of the `maps` relation, and every native form of the `natives` relation. See [marking language, font and mapping](authoring/links-and-markup.md#marking-language-font-and-mapping).
35
35
 
36
36
  Mark a name without a note as `[Name]{.name data-type="being"}`; the optional
37
37
  classification uses the declared note vocabulary. The [name-marking
@@ -175,6 +175,6 @@ Places, affiliations, lore and beings may name their culture in `data.culture`,
175
175
 
176
176
  An affiliation may name the trade, temple or order tongue it keeps in its own `data.language`. An affiliation that reaches no culture is a warning, in a tree holding a culture note. A language needs no culture and no affiliation. See [type: affiliation](reference/format-details.md#type-affiliation).
177
177
 
178
- A language note (`type: skill`, `subType: language`) states its words in frontmatter: `data.words` states each word as a map of its form, class, field and gloss — one sense or a list of them, which a dictionary numbers — with its source, its variant forms, the pieces it is built from and a note, beside `data.classModifiers`, `data.fields` and `data.affixes`, each affix with the `kind` it makes, for a given name's ending who the name is `given` to, and the stem closes it is barred after; a zero affix states `zero: true` and no form. The notes a word is cited from are derived, not written: a note cites a word by marking it in italics in its prose, matched by form or a variant with diacritics and case set aside. The language of a word is the note it sits on, and none of it reaches the compiled Item. A daughter language names its parent in `data.family` and reads the parent's words as its own; the `language_lineage` relation joins a language to its ancestors. Classes come from the [master word classes](reference/format-details.md#word-classes). A culture or an affiliation states its own glossary entries in `data.glossary`: common words in its core vocabulary, dictionary words with a context meaning, or phrases, compounds and terms of art outside the dictionary with their own gloss. An entry naming a word of its resolved language takes the word's senses and class and links to its language entry; a `definition` supplies the entry's meaning instead. Common marks belong to the glossary's owner. A language note with nonempty `data.words` receives its full Dictionary section automatically: one alphabetical list with field tags and one key. A culture or affiliation with nonempty `data.glossary` receives only its explicitly declared entries in its Glossary section; ranks and offices stand in the affiliation's own sections. A note without the relevant frontmatter receives no such section. All surfaces show these sections after the authored text, or under an existing `{#dictionary}`, `{#lexicon}` or `{#glossary}` heading after its introduction. There are no setting-wide dictionary or glossary pages. Every entry resolves to a language — its own `language`, else the affiliation's, its parents' or its culture's, else the culture's — or is an error at the entry. The `words`, `affixes`, `fields`, `glossary` and `language_lineage` relations hold them for `sql` fences, the `dictionary` relation lists each word under every language that has it, inherited words included, and the `terms` relation each glossary entry, rank and office with its culture associations; a fence sets custom views with `layout=dictionary` or `layout=glossary`. A language note names the tag a dictionary prints for it in `data.abbreviation`. Every fact a check reads about a language's names, sounds and history is frontmatter too: `data.tongues` and `data.register` (every name the setting gives in the language's reach, the notes carrying each derived from the index, and a name tagged `other:<tongue>` or `exonym:<tongue>` one that the tongue's own language note registers under that tongue), `data.retired`, `data.scope`, `data.sounds` (letters with their place, word edges from a closed list, the cluster limit and the groups of clusters inside a word, the stress rule, syllable finals, syllable rules and vowel harmony with each vowel's front partner, the joining of parts, written marks, a root's skeleton vowel and frames, the spellings read past, and named mutations such as wearing and voicing), `data.soundChanges` (named sets of ordered steps), `data.elements` (each standing `opening`, `closing`, `either` or `link`, for one kind of name, with the word it is the stem of and its joining form), `data.roots`, `data.cognates` (with a reconstructed `proto` form), `data.callingNames`, `data.older` (the forms older than the rules), `data.negation` (the negative particle and the mutation it brings) and `data.naming` (how long each class of name runs, the edges names keep that words do not, the element kinds each kind of name draws on, what a place name takes from what it is held from, and the near name), each a relation — `sounds` as `letters`, `edges`, `clusters`, `cluster_groups`, `stress`, `finals`, `syllables`, `joining`, `joins`, `marks`, `skeleton`, `frames`, `read_past` and `mutations`, `soundChanges` as `sound_changes`, `callingNames` as `calling_names` — that a fence sets back on the page. A word's citations also come from a note whose name, alias or rank or office title spells it whole. See [a language's words](reference/format-details.md#a-languages-words), [a language's register, sounds and history](reference/format-details.md#a-languages-register-sounds-and-history), [glossary terms](reference/format-details.md#glossary-terms) and [dictionaries and glossaries](reference/format-details.md#dictionaries-and-glossaries).
178
+ A language note (`type: skill`, `subType: language`) states its words in frontmatter: `data.words` states each word as a map of its form, class, field and gloss — one sense or a list of them, which a dictionary numbers — with its source, its variant forms, the pieces it is built from and a note, beside `data.classModifiers`, `data.fields` and `data.affixes`, each affix with the `kind` it makes, for a given name's ending who the name is `given` to, and the stem closes it is barred after; a zero affix states `zero: true` and no form. The notes a word is cited from are derived, not written: a note cites a word by marking it in italics in its prose, matched by form or a variant with diacritics and case set aside. The language of a word is the note it sits on, and none of it reaches the compiled Item. A daughter language names its parent in `data.family` and reads the parent's words as its own; the `language_lineage` relation joins a language to its ancestors. Classes come from the [master word classes](reference/format-details.md#word-classes). A culture or an affiliation states its own glossary entries in `data.glossary`: common words in its core vocabulary, dictionary words with a context meaning, or phrases, compounds and terms of art outside the dictionary with their own gloss. An entry naming a word of its resolved language takes the word's senses and class and links to its language entry; a `definition` supplies the entry's meaning instead. Common marks belong to the glossary's owner. A language note with nonempty `data.words` receives its full Dictionary section automatically: one alphabetical list with field tags and one key. A culture or affiliation with nonempty `data.glossary` receives only its explicitly declared entries in its Glossary section; ranks and offices stand in the affiliation's own sections. A note without the relevant frontmatter receives no such section. All surfaces show these sections after the authored text, or under an existing `{#dictionary}`, `{#lexicon}` or `{#glossary}` heading after its introduction. There are no setting-wide dictionary or glossary pages. Every entry resolves to a language — its own `language`, else the affiliation's, its parents' or its culture's, else the culture's — or is an error at the entry. The `words`, `affixes`, `fields`, `glossary` and `language_lineage` relations hold them for `sql` fences, the `dictionary` relation lists each word under every language that has it, inherited words included, and the `terms` relation each glossary entry, rank and office with its culture associations; a fence sets custom views with `layout=dictionary` or `layout=glossary`. A language note names the tag a dictionary prints for it in `data.abbreviation`. A `doc` note states a setting's core concepts in `data.concepts`, a language note says it must cover them with `data.core: true`, and a word names the concepts it serves in `concept`; `package-build core` lists what each covering language has no word for (see [the core vocabulary](reference/format-details.md#the-core-vocabulary)). Every fact a check reads about a language's names, sounds and history is frontmatter too: `data.tongues` and `data.register` (every name the setting gives in the language's reach, the notes carrying each derived from the index, and a name tagged `other:<tongue>` or `exonym:<tongue>` one that the tongue's own language note registers under that tongue), `data.retired`, `data.scope`, `data.sounds` (letters with their place, word edges from a closed list, the cluster limit and the groups of clusters inside a word, the stress rule (`two`, `longer` and `mark`), syllable finals, syllable rules and vowel harmony with each vowel's front partner, the joining of parts, written marks, a root's skeleton vowel and frames, the spellings read past, and named mutations such as wearing and voicing), `data.soundChanges` (named sets of ordered steps), `data.elements` (each standing `opening`, `closing`, `either` or `link`, for one kind of name, with the word it is the stem of and its joining form), `data.roots`, `data.cognates` (with a reconstructed `proto` form), `data.callingNames`, `data.older` (the forms older than the rules), `data.negation` (the negative particle and the mutation it brings) and `data.naming` (how long each class of name runs, the edges names keep that words do not, the element kinds each kind of name draws on, what a place name takes from what it is held from, and the near name), each a relation — `sounds` as `letters`, `edges`, `clusters`, `cluster_groups`, `stress`, `finals`, `syllables`, `joining`, `joins`, `marks`, `skeleton`, `frames`, `read_past` and `mutations`, `soundChanges` as `sound_changes`, `callingNames` as `calling_names` — that a fence sets back on the page. A word's citations also come from a note whose name, alias or rank or office title spells it whole. See [a language's words](reference/format-details.md#a-languages-words), [a language's register, sounds and history](reference/format-details.md#a-languages-register-sounds-and-history), [glossary terms](reference/format-details.md#glossary-terms) and [dictionaries and glossaries](reference/format-details.md#dictionaries-and-glossaries).
179
179
 
180
180
  Blockquote alerts use `[!NOTE]`, `[!TIP]`, `[!IMPORTANT]`, `[!WARNING]`, or `[!]`, with optional attributes after the marker. They replace the former info and warn div fences; secret blocks remain supported. See [alerts](authoring/links-and-markup.md#alerts).
@@ -330,7 +330,7 @@ lint`, `package-build lang check`, `package-build lang coverage`,
330
330
  and returns only the count whose `severity` is `error`, and the command sets
331
331
  `process.exitCode = 1` exactly when that count is nonzero. Commands whose
332
332
  findings are hand-assembled — `package-build links`, `package-build
333
- reachability`, `package-build site`, `package-build package compile` — apply
333
+ reachability`, `package-build site build`, `package-build package compile` — apply
334
334
  the same rule by construction: everything they can report is a broken
335
335
  address, a dead link or a document Foundry would silently drop a field from,
336
336
  so every finding they emit is already `severity: "error"` and any finding at
@@ -368,7 +368,7 @@ over one would teach people to stop reading the report.
368
368
  | `package-build addresses diff --from <artifact>` | the corpus cannot be indexed (always); otherwise only with `--strict`, and only then are the address findings `error`-severity |
369
369
  | `package-build format [paths..]` | a file it checked is not formatted (or, under `--write`, could not be brought to a fixpoint) — never on a shared-convention divergence, which is always advisory |
370
370
  | `package-build markdown [paths..]` | it reports any markdownlint finding |
371
- | `package-build site` | any gate finding (no homepage, a wikilink in frontmatter, an address that cannot be derived, an unusable or unaddressable foreign manifest, a conflicting address) or any table or wikilink error while writing pages — the run stops at the first gate that fires |
371
+ | `package-build site build` | any gate finding (no homepage, a wikilink in frontmatter, an address that cannot be derived, an unusable or unaddressable foreign manifest, a conflicting address) or any table or wikilink error while writing pages — the run stops at the first gate that fires |
372
372
  | `package-build pdf` | it could not build the book for a reason other than a deliberate no-op — never on a reported finding by itself |
373
373
  | `package-build map` | `--tree` reports an `error`-severity finding (a place with no parent, a parent that does not resolve, a cycle), a named place is not one, the renderer fails, or the corpus cannot be indexed — never on a warning |
374
374
  | `package-build docs item-fields --check` | the generated page differs from what is committed |
@@ -15,7 +15,7 @@ subType: userguide
15
15
  | A Foundry module, with or without source code | [Module project](guides/module-project.md) |
16
16
  | Notes in an existing package | [Your first note](authoring/first-note.md) |
17
17
 
18
- Node 24 or newer and npm are needed for the toolchain. The generated website build uses Hugo Extended; the book build uses Typst. A Foundry installation and deployment credentials are not needed to author or build content locally.
18
+ Node 24 or newer and npm are needed for the toolchain. The book build uses Typst. A Foundry installation and deployment credentials are not needed to author or build content locally.
19
19
 
20
20
  ## Start a package
21
21
 
@@ -130,7 +130,7 @@ Run the content lint and build the surfaces the package publishes:
130
130
  ```bash
131
131
  package-build lint
132
132
  package-build package compile
133
- package-build site
133
+ package-build site build
134
134
  package-build pdf --no-compile
135
135
  ```
136
136
 
@@ -25,7 +25,7 @@ npm run lint
25
25
  The generated project includes a homepage, an introduction, a website build,
26
26
  and a book build. Run `npm run build:site` to produce the site,
27
27
  `npm run serve:site` to view it locally, or `npm run build:book` for a PDF.
28
- Those commands require Hugo Extended and Typst respectively. Run
28
+ The book build requires Typst. Run
29
29
  `package-build init --check` to inspect the project without changing it. See
30
30
  [`init`](../commands.md#package-build-init-directory) for the package kinds,
31
31
  interactive prompts, and collision rules.
@@ -891,11 +891,8 @@ address to `package.json` as `homepage`, with a `description` beside it, list
891
891
  the package's people in `authors` in `package-build.config.yaml`, and add a
892
892
  `packageBuild.manifest.title`. The theme the site renders
893
893
  through ships with this package, so nothing else is installed. Then `package-build deps fetch` caches the
894
- organisation's navigation, and `package-build site` writes the whole Hugo
895
- source tree under `build/hugo/` — the configuration generated from those
896
- values, and the content mount — for `hugo --source build/hugo` to render
897
- into `build/site/<contentPackage>/`. There is no Hugo configuration to
898
- write: the file is generated on every run, and what is genuinely the
894
+ organisation's navigation, and `package-build site build` renders the site
895
+ into `build/site/<contentPackage>/` from those values. What is genuinely the
899
896
  package's own — the wording of its "page not found" page — goes in the
900
897
  `site:` block as `site.notfound`. The same command publishes the content tree's
901
898
  every page beside the homepage — one
@@ -935,7 +932,7 @@ Everything in steps 4 and 8 that exists to describe a Foundry package is
935
932
  tree supplies its site pages and book entries.
936
933
 
937
934
  So a documentation package's configuration is steps 1 through 6 with a different
938
- `packageKind`, plus a `site:` block, and then `package-build site` in place of
935
+ `packageKind`, plus a `site:` block, and then `package-build site build` in place of
939
936
  steps 7 through 11. [`configuration.md`](../configuration.md) carries the refusal
940
937
  message for every key; [`commands.md`](../commands.md) covers the two commands such
941
- a package lives on, `package-build site` and `package-build pdf`.
938
+ a package lives on, `package-build site build` and `package-build pdf`.
@@ -199,9 +199,9 @@ desk:
199
199
  - **`npm run build`** runs `package-build ci`: the Build & Test workflow's
200
200
  `run:` steps in a `linux/amd64` container over a clean export of `HEAD`.
201
201
  `npm run build -- --native` runs them on the host in the working tree instead.
202
- Off Linux, the Typst, GraphViz and Hugo steps install nothing; each uses the
202
+ Off Linux, the Typst and GraphViz steps install nothing; each uses the
203
203
  tool already on `PATH` and stops with `<tool> is not on PATH` when it is
204
- missing, so a Mac running `--native` needs `typst`, `dot` and Hugo extended
204
+ missing, so a Mac running `--native` needs `typst` and `dot`
205
205
  installed first.
206
206
  - **`npm run deploy:npm`** runs `npm publish`. Provenance is attested only on a
207
207
  CI runner that can mint a Sigstore identity — GitHub Actions with an OIDC