@heroiclands/package-build 22.15.0 → 22.16.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 (223) hide show
  1. package/CHANGELOG.md +103 -0
  2. package/README.md +39 -678
  3. package/bin/{content-build.mjs → content-commands.mjs} +197 -118
  4. package/bin/package-build.mjs +303 -42
  5. package/bin/report.mjs +1 -1
  6. package/ci/ci-docker.mjs +6 -3
  7. package/ci/ci-steps.mjs +6 -4
  8. package/ci/content-format-reference.mjs +106 -0
  9. package/config.mjs +22 -2
  10. package/content-config.mjs +74 -134
  11. package/docs/api.md +294 -234
  12. package/docs/authoring/assets.md +31 -0
  13. package/docs/authoring/dates-and-calendars.md +33 -0
  14. package/docs/authoring/first-note.md +48 -0
  15. package/docs/authoring/frontmatter.md +40 -0
  16. package/docs/authoring/links-and-markup.md +137 -0
  17. package/docs/commands.md +631 -162
  18. package/docs/configuration.md +176 -140
  19. package/docs/content-format.md +50 -4229
  20. package/docs/design.md +32 -0
  21. package/docs/diagnostics.md +29 -22
  22. package/docs/getting-started.md +21 -877
  23. package/docs/guides/book.md +153 -0
  24. package/docs/guides/e2e.md +143 -0
  25. package/docs/guides/icons.md +126 -0
  26. package/docs/guides/localization.md +120 -0
  27. package/docs/guides/module-project.md +915 -0
  28. package/docs/guides/packs.md +167 -0
  29. package/docs/guides/reference-pages.md +148 -0
  30. package/docs/guides/release-and-deploy.md +114 -0
  31. package/docs/guides/site.md +152 -0
  32. package/docs/guides/system-project.md +45 -0
  33. package/docs/index.md +16 -0
  34. package/docs/project-setup.md +54 -35
  35. package/docs/reference/format-details.md +4420 -0
  36. package/docs/reference/note-types.md +531 -0
  37. package/engine/address-render.mjs +26 -0
  38. package/engine/address.mjs +3 -20
  39. package/engine/anchors.mjs +15 -6
  40. package/engine/asset-bindings.mjs +6 -2
  41. package/engine/base-compiler.mjs +47 -11
  42. package/engine/being-measurements.mjs +70 -0
  43. package/engine/calendar-artifacts.mjs +1 -1
  44. package/engine/calendar-choice.mjs +32 -0
  45. package/engine/calendar-human.mjs +71 -0
  46. package/engine/calendar-notes.mjs +41 -3
  47. package/engine/calendars.mjs +8 -1
  48. package/engine/changelog-lint.mjs +2 -2
  49. package/engine/code-fences.mjs +23 -97
  50. package/engine/compile-corpus.mjs +6 -7
  51. package/engine/content-admonitions.mjs +114 -0
  52. package/engine/content-captions.mjs +181 -0
  53. package/engine/content-embeds.mjs +2 -2
  54. package/engine/content-footnotes.mjs +34 -0
  55. package/engine/content-format-check.mjs +2 -2
  56. package/engine/content-format.mjs +127 -73
  57. package/engine/content-format.yaml +745 -0
  58. package/engine/content-html.mjs +1 -1
  59. package/engine/content-icons.mjs +45 -92
  60. package/engine/content-images.mjs +22 -74
  61. package/engine/content-index.mjs +12 -3
  62. package/engine/content-links.mjs +21 -26
  63. package/engine/content-lint.mjs +1 -5
  64. package/engine/content-secrets.mjs +3 -1
  65. package/engine/content-tables.mjs +47 -1257
  66. package/engine/culture-choice.mjs +32 -0
  67. package/engine/date-conversion.mjs +47 -0
  68. package/engine/declaration-check.mjs +87 -0
  69. package/engine/docs-checks.mjs +140 -0
  70. package/engine/documentation-links.mjs +31 -0
  71. package/engine/exported-scene.mjs +1 -1
  72. package/engine/extension-attributes.mjs +74 -0
  73. package/engine/field-reference.mjs +1 -1
  74. package/engine/field-spec.mjs +4 -0
  75. package/engine/foreign-catalog.mjs +5 -5
  76. package/engine/format-generated.mjs +15 -0
  77. package/engine/foundry-entries.mjs +3 -1
  78. package/engine/frontmatter-lint.mjs +5 -1
  79. package/engine/frontmatter.mjs +10 -0
  80. package/engine/generate.mjs +2 -2
  81. package/engine/helpers.mjs +71 -117
  82. package/engine/homepage.mjs +2 -3
  83. package/engine/index-records.mjs +1 -0
  84. package/engine/index.mjs +18 -3
  85. package/engine/infobox-registry.mjs +3 -1
  86. package/engine/infobox.mjs +38 -20
  87. package/engine/item-compiler.mjs +10 -8
  88. package/engine/item-docs.mjs +7 -6
  89. package/engine/itinerary-scenes.mjs +4 -2
  90. package/engine/journals.mjs +51 -10
  91. package/engine/macros.mjs +1 -1
  92. package/engine/map-build.mjs +1 -1
  93. package/engine/map-dot.mjs +1 -1
  94. package/engine/map-raster.mjs +4 -2
  95. package/engine/markdown-expressions.mjs +117 -0
  96. package/engine/metadata-index.mjs +7 -3
  97. package/engine/note-addresses.mjs +1 -0
  98. package/engine/note-dates.mjs +283 -61
  99. package/engine/note-package.mjs +5 -25
  100. package/engine/note-state.mjs +6 -2
  101. package/engine/note-vocabulary.mjs +74 -19
  102. package/engine/number-words.mjs +75 -0
  103. package/engine/office-holders.mjs +188 -0
  104. package/engine/pack-config.mjs +2 -15
  105. package/engine/pack-router.mjs +24 -5
  106. package/engine/packages.mjs +3 -2
  107. package/engine/pathnames.mjs +21 -24
  108. package/engine/pdf-build.mjs +217 -55
  109. package/engine/pdf-fonts.mjs +2 -2
  110. package/engine/pdf-images.mjs +82 -0
  111. package/engine/pdf-render.mjs +174 -22
  112. package/engine/populations.mjs +3 -2
  113. package/engine/project-init.mjs +499 -0
  114. package/engine/prose-config.mjs +1 -1
  115. package/engine/prose-lint.mjs +7 -6
  116. package/engine/readability-lint.mjs +86 -0
  117. package/engine/reckoning-markers.mjs +205 -93
  118. package/engine/scenes.mjs +5 -2
  119. package/engine/schema-check.mjs +3 -3
  120. package/engine/site-build.mjs +87 -37
  121. package/engine/site-config.mjs +8 -8
  122. package/engine/site-index.mjs +4 -0
  123. package/engine/site-maps.mjs +1 -1
  124. package/engine/site-preview.mjs +19 -8
  125. package/engine/social-ties.mjs +5 -1
  126. package/engine/sql-tables.mjs +92 -22
  127. package/engine/web-wikilinks.mjs +15 -31
  128. package/engine/wikilink-syntax.mjs +4 -1
  129. package/engine/wikilinks.mjs +12 -14
  130. package/hm3/item-fields.mjs +1 -1
  131. package/hm3/items.mjs +12 -45
  132. package/index.mjs +2 -14
  133. package/manifest.mjs +31 -4
  134. package/markdownlint-config.mjs +1 -1
  135. package/package.json +32 -11
  136. package/prettier-config.mjs +1 -1
  137. package/sohl/being-info.mjs +3 -145
  138. package/sohl/index.mjs +1 -1
  139. package/sohl/infobox.mjs +2 -1
  140. package/sohl/item-builders.mjs +3 -27
  141. package/sohl/item-fields.mjs +61 -22
  142. package/sohl/kb-passes.mjs +2 -2
  143. package/sohl/note-schemas.mjs +0 -8
  144. package/stage.mjs +19 -0
  145. package/types/config.d.mts +12 -3
  146. package/types/content-config.d.mts +15 -81
  147. package/types/engine/address-render.d.mts +13 -0
  148. package/types/engine/address.d.mts +2 -11
  149. package/types/engine/anchors.d.mts +3 -4
  150. package/types/engine/asset-bindings.d.mts +9 -2
  151. package/types/engine/base-compiler.d.mts +1 -2
  152. package/types/engine/being-measurements.d.mts +16 -0
  153. package/types/engine/calendar-choice.d.mts +14 -0
  154. package/types/engine/calendar-human.d.mts +4 -0
  155. package/types/engine/calendar-notes.d.mts +2 -0
  156. package/types/engine/calendars.d.mts +5 -3
  157. package/types/engine/code-fences.d.mts +6 -72
  158. package/types/engine/compile-corpus.d.mts +1 -3
  159. package/types/engine/content-admonitions.d.mts +24 -0
  160. package/types/engine/content-captions.d.mts +45 -0
  161. package/types/engine/content-footnotes.d.mts +10 -0
  162. package/types/engine/content-format-check.d.mts +17 -4
  163. package/types/engine/content-format.d.mts +24 -11
  164. package/types/engine/content-icons.d.mts +14 -23
  165. package/types/engine/content-images.d.mts +2 -2
  166. package/types/engine/content-index.d.mts +9 -2
  167. package/types/engine/content-links.d.mts +3 -5
  168. package/types/engine/content-tables.d.mts +11 -140
  169. package/types/engine/culture-choice.d.mts +14 -0
  170. package/types/engine/date-conversion.d.mts +4 -0
  171. package/types/engine/declaration-check.d.mts +24 -0
  172. package/types/engine/docs-checks.d.mts +28 -0
  173. package/types/engine/documentation-links.d.mts +7 -0
  174. package/types/engine/exported-scene.d.mts +6 -2
  175. package/types/engine/extension-attributes.d.mts +14 -0
  176. package/types/engine/field-spec.d.mts +9 -0
  177. package/types/engine/format-generated.d.mts +7 -0
  178. package/types/engine/frontmatter.d.mts +14 -4
  179. package/types/engine/generate.d.mts +1 -1
  180. package/types/engine/helpers.d.mts +37 -92
  181. package/types/engine/homepage.d.mts +2 -3
  182. package/types/engine/index.d.mts +5 -0
  183. package/types/engine/infobox-registry.d.mts +3 -1
  184. package/types/engine/infobox.d.mts +17 -6
  185. package/types/engine/item-compiler.d.mts +4 -4
  186. package/types/engine/item-docs.d.mts +4 -3
  187. package/types/engine/journals.d.mts +10 -7
  188. package/types/engine/map-graphviz.d.mts +1 -1
  189. package/types/engine/markdown-expressions.d.mts +17 -0
  190. package/types/engine/note-dates.d.mts +47 -1
  191. package/types/engine/note-package.d.mts +3 -19
  192. package/types/engine/note-state.d.mts +2 -1
  193. package/types/engine/note-vocabulary.d.mts +9 -0
  194. package/types/engine/number-words.d.mts +4 -0
  195. package/types/engine/office-holders.d.mts +14 -0
  196. package/types/engine/pack-config.d.mts +1 -1
  197. package/types/engine/packages.d.mts +3 -2
  198. package/types/engine/pdf-images.d.mts +38 -0
  199. package/types/engine/populations.d.mts +2 -2
  200. package/types/engine/project-init.d.mts +17 -0
  201. package/types/engine/prose-config.d.mts +1 -1
  202. package/types/engine/prose-lint.d.mts +3 -2
  203. package/types/engine/readability-lint.d.mts +22 -0
  204. package/types/engine/reckoning-markers.d.mts +4 -2
  205. package/types/engine/schema-check.d.mts +3 -3
  206. package/types/engine/site-build.d.mts +38 -28
  207. package/types/engine/site-config.d.mts +2 -2
  208. package/types/engine/site-index.d.mts +4 -0
  209. package/types/engine/site-preview.d.mts +1 -1
  210. package/types/engine/social-ties.d.mts +8 -2
  211. package/types/engine/sql-tables.d.mts +13 -2
  212. package/types/engine/web-wikilinks.d.mts +2 -1
  213. package/types/engine/wikilinks.d.mts +7 -1
  214. package/types/hm3/items.d.mts +5 -6
  215. package/types/labels.d.mts +40 -0
  216. package/types/manifest.d.mts +3 -3
  217. package/types/sohl/actors.d.mts +2 -2
  218. package/types/sohl/being-info.d.mts +3 -43
  219. package/types/sohl/index.d.mts +1 -1
  220. package/types/sohl/infobox.d.mts +5 -2
  221. package/types/sohl/item-fields.d.mts +4 -13
  222. package/types/stage.d.mts +9 -0
  223. package/CONTENT.md +0 -3239
@@ -0,0 +1,153 @@
1
+ ---
2
+ shortcode: guidesbook
3
+ name: { full: "Build a PDF book" }
4
+ type: doc
5
+ subType: howto
6
+ ---
7
+
8
+ # Build a PDF book
9
+
10
+ `package-build pdf` selects notes from a content package and sets them as a
11
+ PDF. The website can publish the whole content tree; the book follows the
12
+ ordered document tree named by `pdf.document`. This makes the book's contents
13
+ an editorial choice. A note outside every selection remains in the content
14
+ package and on its site, but it has no book entry.
15
+
16
+ The build writes Typst source under `pdf.out` and invokes the Typst binary to
17
+ produce the PDF. Typst must be available on `PATH`, or named with `pdf.binary`.
18
+ The [command reference](../commands.md) lists the CLI options; the
19
+ [configuration reference](../configuration.md) lists the `pdf` keys.
20
+
21
+ ## Declare the book
22
+
23
+ Give the book a title and document tree:
24
+
25
+ ```yaml
26
+ pdf:
27
+ title: The Setting Guide
28
+ document: book.yaml
29
+ out: build/pdf
30
+ ```
31
+
32
+ A tree containing only a homepage has no content pages for a book. With no
33
+ `pdf` block or no content tree, the command has nothing to build. `pdf.title`
34
+ and `pdf.document` are required together when `pdf` is declared.
35
+
36
+ `book.yaml` contains an ordered list of sections. Each section contains prose
37
+ files, note filters, or nested sections:
38
+
39
+ ```yaml
40
+ contents:
41
+ - sectionName: Introduction
42
+ contents:
43
+ - file: prose/introduction.md
44
+ - sectionName: Places
45
+ contents:
46
+ - filter: "type = 'place'"
47
+ - sectionName: Settlements
48
+ contents:
49
+ - filter: "type = 'place' AND subType = 'settlement'"
50
+ ```
51
+
52
+ The build keeps the order of prose and subsections as written. Notes selected
53
+ by a filter are ordered by their folded display name. The filter is a SQL
54
+ `WHERE` clause over this package's `notes` table; the build supplies
55
+ `SELECT * FROM notes`. A filter cannot choose another package's notes. It is
56
+ an error when a filter selects no printable note, while notes that no filter
57
+ selects are simply outside this volume. A note selected more than once prints
58
+ at each selected position; inbound book links reach its first occurrence.
59
+
60
+ The document tree can include a section with prose and no selected notes, for
61
+ example a preface. Empty sections do not print. `pdf.front` lists Markdown
62
+ files placed before the book's contents.
63
+
64
+ ## Control a section's page
65
+
66
+ Sections can provide a running footer and page presentation:
67
+
68
+ ```yaml
69
+ contents:
70
+ - sectionName: Places
71
+ footer: The Atlas
72
+ page:
73
+ banner: assets/images/banners/atlas.webp
74
+ kicker: The Atlas
75
+ columns: 2
76
+ contents:
77
+ - filter: "type = 'place'"
78
+ ```
79
+
80
+ `page.columns` accepts one through four columns. The ordinary page uses two.
81
+ `page.banner` names an image the package ships, and `page.kicker` supplies the
82
+ line above an entry title. A subsection inherits presentation from its
83
+ ancestors; a declared `page` block replaces the inherited block as a whole,
84
+ so it states every page option that subsection wants. A section without a
85
+ banner still has a title plate. A banner path that cannot be read is a
86
+ finding.
87
+
88
+ Each section and each selected entry starts on its own page. The PDF has a
89
+ contents page and an outline for section and entry navigation. A note's
90
+ `description` appears as an epigraph when present. Wider tables span both
91
+ columns; an uncaptioned wide table starts on a new page so it stays after its
92
+ introduction. A captioned wide table may float to the page top, and its numbered
93
+ caption stays with it. A table too tall for one page takes pages of its own.
94
+ Caption numbers run through the whole book in reading order. Maps attached
95
+ to selected places use landscape pages after those entries. Regional, theatre
96
+ of the mind, battle, and local map backgrounds also print on landscape pages.
97
+ Battle and local maps print each Scene level's background on its own page.
98
+ The
99
+ [content format](../content-format.md) describes image sizes, floats, and
100
+ links as they are authored in notes.
101
+
102
+ The book stages raster art at up to 300 dpi for its largest printed use.
103
+ Ordinary images fit their column, full-width images fit the page's text width,
104
+ and map backgrounds fit the landscape map area. An image smaller than that
105
+ target keeps its authored pixels and still fills its allotted space on the
106
+ page. SVG art stays vector. The build never changes authored image files.
107
+
108
+ ## Set fonts and icon fonts
109
+
110
+ The build supplies its default book fonts and searches its own font directory
111
+ for them. A package can choose families and add a font directory:
112
+
113
+ ```yaml
114
+ pdf:
115
+ title: The Setting Guide
116
+ document: book.yaml
117
+ fonts:
118
+ serif: Libertinus Serif
119
+ sans: Libertinus Sans
120
+ mono: DejaVu Sans Mono
121
+ path: assets/fonts
122
+ iconFonts:
123
+ fontawesome: assets/fonts/fa-solid-900.ttf
124
+ ```
125
+
126
+ The `fonts` values are family names; `fonts.path` is a directory to search.
127
+ `iconFonts` maps an icon family to the file carrying its glyphs. The Typst
128
+ invocation ignores system-installed fonts, so a machine's font collection
129
+ does not silently change the book. Check a chosen font's coverage for the
130
+ characters in the notes: Typst can substitute a face and still exit
131
+ successfully. The [content format](../content-format.md) covers icon names
132
+ written in notes; the [configuration reference](../configuration.md) covers
133
+ the font registry.
134
+
135
+ ## Build and inspect
136
+
137
+ ```bash
138
+ package-build pdf
139
+ package-build pdf --no-compile
140
+ package-build pdf --out build/book
141
+ ```
142
+
143
+ `--no-compile` emits the Typst source and staged images without invoking
144
+ Typst. The source and assets sit under the output directory, because Typst
145
+ reads paths relative to its compilation root. An authored image from this
146
+ package can be staged into the book. A remote image or one owned by another
147
+ package cannot be read by this build; the build reports that limitation.
148
+
149
+ Wikilinks between selected notes become internal PDF destinations. A link to
150
+ a note outside the selection or another package remains a web address.
151
+ Anchors on headings are scoped to their entries, so two entries can use the
152
+ same heading anchor. The build reports an unresolved destination while
153
+ keeping the source available for inspection.
@@ -0,0 +1,143 @@
1
+ ---
2
+ shortcode: guidese2e
3
+ name: { full: "Test a package in Foundry" }
4
+ type: doc
5
+ subType: howto
6
+ ---
7
+
8
+ # Test a package in Foundry
9
+
10
+ `package-build e2e` serves a staged package in a disposable Foundry world and
11
+ hands control to the repository's browser suite. The harness owns deployment,
12
+ world seeding, container lifecycle, and the wait for an active world. The
13
+ repository chooses the suite command, build targets, and result files. See the
14
+ [e2e command](../commands.md#package-build-e2e-action) and
15
+ [configuration reference](../configuration.md#packagebuilde2e) for the full
16
+ contract.
17
+
18
+ ## Configure the suite
19
+
20
+ Declare a headless runner, and optionally an interactive one. The suite
21
+ command is an argument array, so each item is one process argument:
22
+
23
+ ```yaml
24
+ packageBuild:
25
+ e2e:
26
+ suite:
27
+ run: [npx, cypress, run]
28
+ open: [npx, cypress, open]
29
+ results: [cypress/results]
30
+ build:
31
+ code: { script: build:code, recreate: true }
32
+ packs: build:db
33
+ ```
34
+
35
+ Here `build:code` and `build:db` are scripts in the consuming repository's
36
+ `package.json`. The `build` mapping is ordered: a `fast` run executes targets
37
+ in that order even when they are requested in another order. Mark a target
38
+ `recreate: true` when it changes something Foundry reads only when the world
39
+ starts, such as the manifest. Configure the runner to write to the paths in
40
+ `results`; the example runner writes to `cypress/results`. A zero exit with no
41
+ fresh result in those paths is reported as
42
+ a failed run; the harness also checks that the runner executable remains
43
+ installed through the run.
44
+
45
+ The optional `world`, `gm`, and `documents` mappings set the disposable
46
+ world's identity, GM credentials, and seeded collections. With no override,
47
+ the world is named from the package and includes a GM and active scene. A
48
+ module package is enabled in that world. The harness does not supply a
49
+ Cypress test suite; `suite.run` and `suite.open` name the repository's own.
50
+
51
+ ## Keep local settings in `.env.local`
52
+
53
+ Create `.env.local` at the repository root with a data directory reserved for
54
+ this harness and a Foundry license available to the test container:
55
+
56
+ ```dotenv
57
+ FOUNDRYVTT_TEST_DATA=/path/to/isolated-foundry-test-data
58
+ FOUNDRYVTT_TEST_LICENSE_KEY=replace-with-test-license-key
59
+ FOUNDRYVTT_TEST_PORT=30003
60
+ # FOUNDRYVTT_TEST_VERSION=14.367
61
+ ```
62
+
63
+ Keep `.env.local` ignored by git; it holds machine-specific paths and real
64
+ credentials. `package-build init` creates this basic `.gitignore` skeleton:
65
+
66
+ ```gitignore
67
+ node_modules
68
+ /build/
69
+ /nogit/
70
+ /.env*
71
+ /.DS_Store
72
+ /.claude/
73
+ *.tgz
74
+ ```
75
+
76
+ `/.env*` covers `.env.local`, `.env`, and other local environment files.
77
+ `/build/` keeps generated indexes, packs, site files, and books out of commits;
78
+ `/nogit/` reserves local scratch. The CLI reads `.env.local` from the
79
+ configured repository root before `.env`. Values already set in the shell take precedence over both files, and
80
+ `.env.local` takes precedence over `.env`. A separate git worktree needs its
81
+ own `.env.local` because that ignored file is not copied with the branch.
82
+ The test data path is a Foundry data root, beneath which the harness creates
83
+ `Data/worlds/` and installs the package. Use an absolute path; `~` and shell
84
+ variables are not expanded in `.env.local`. Set `FOUNDRYVTT_TEST_VERSION` to
85
+ select a specific Foundry build for routine runs. With the local settings in
86
+ place, seed the world:
87
+
88
+ ```bash
89
+ package-build e2e seed
90
+ ```
91
+
92
+ The seed command writes the disposable world beneath that data root. It
93
+ replaces the seeded world with the same ID each time. The harness refuses a
94
+ root shared with another Foundry stage, so test seeding cannot overwrite a
95
+ development or production world.
96
+
97
+ ## Run the whole suite
98
+
99
+ Build the staged package first, then use one of the full-run modes:
100
+
101
+ ```bash
102
+ package-build e2e run
103
+ package-build e2e open
104
+ ```
105
+
106
+ `run` deploys the stage, reseeds the world, recreates the container, waits for
107
+ the world to become active, runs the headless suite, and stops the container.
108
+ `open` uses the same setup and launches `suite.open`; it leaves the server up
109
+ for interactive testing. Arguments after `--` are passed to the suite, for
110
+ example `package-build e2e run -- --browser chrome`. A port answering is not
111
+ enough: the harness waits until Foundry's join page shows the world is active.
112
+
113
+ ## Iterate without reseeding
114
+
115
+ `fast` rebuilds declared targets, redeploys the full stage, cycles the world,
116
+ waits for it, and runs the headless suite:
117
+
118
+ ```bash
119
+ package-build e2e fast
120
+ package-build e2e fast --build=packs -- --spec cypress/e2e/items.cy.js
121
+ package-build e2e fast --build=none --no-run
122
+ ```
123
+
124
+ `--build=` takes declared target names, a comma-separated subset, `all`, or
125
+ `none`. `--no-run` updates the environment without launching the suite.
126
+ `--recreate` forces a fresh container even when the selected targets do not
127
+ require it. This mode keeps the existing seeded world's Foundry generation;
128
+ use a full run when changing the Foundry build.
129
+
130
+ ## Verify another Foundry build
131
+
132
+ Name an exact Foundry build for a compatibility sweep:
133
+
134
+ ```bash
135
+ package-build e2e sweep 14.367
136
+ ```
137
+
138
+ The sweep runs the full reseeded suite with that build for this invocation
139
+ only. It does not change the repository's compatibility declaration. A bare
140
+ major version or moving tag is refused, because the result must name the
141
+ build actually tested. A passing sweep provides evidence for choosing a
142
+ new `compatibility.verified` value; a routine run exercises the pinned
143
+ minimum build.
@@ -0,0 +1,126 @@
1
+ ---
2
+ shortcode: guidesicons
3
+ name: { full: "Icons and artwork" }
4
+ type: doc
5
+ subType: howto
6
+ ---
7
+
8
+ # Icons and artwork
9
+
10
+ Content uses two kinds of icons. An **asset icon** is an image file with an
11
+ address, suitable for a sheet portrait, token, or embedded picture. An **inline
12
+ icon** is a named font glyph in prose, such as the symbol beside an interface
13
+ control. They have different sources and different authoring syntax.
14
+
15
+ The [content format](../content-format.md) defines addresses, art slots, and
16
+ image embeds. The [configuration reference](../configuration.md) defines the
17
+ icon registry and PDF font settings.
18
+
19
+ ## Give an image an address
20
+
21
+ Put a small image under `assets/icons/` and use its filename without the
22
+ extension as its shortcode. For example,
23
+ `assets/icons/tools/anvil.svg` has the address
24
+ `<package>-none-icon-anvil`. Directories beneath `assets/icons/` do not enter
25
+ the address, so filenames must be unique across that root. Larger illustrations
26
+ belong under `assets/images/` and have type `image`. Both types can be used in
27
+ art slots, but a bare value takes the slot's default type.
28
+
29
+ ```yaml
30
+ shortcode: smith
31
+ name: { full: The Smith }
32
+ type: being
33
+ subType: character
34
+ data:
35
+ icon: anvil
36
+ tokenIcon: image-smith-token
37
+ ```
38
+
39
+ Here `data.icon` resolves an `icon` asset and `data.tokenIcon` resolves an
40
+ `image` asset. A full address, such as `sohl-none-image-smith-token`, names
41
+ another package when that package is available to the build. `data.icon` and
42
+ `data.tokenIcon` default to the `icon` type; `data.bgImage` and `data.banner`
43
+ default to `image`. An explicit `image-` or `icon-` type works in any of the
44
+ four slots. A pathname with slashes or an extension is not an art-slot address.
45
+
46
+ | Art slot | Its use |
47
+ | ---------------- | ----------------------------------------------- |
48
+ | `data.icon` | Profile art on a compiled Actor or Item |
49
+ | `data.tokenIcon` | Actor token art; follows `data.icon` when unset |
50
+ | `data.bgImage` | Background of a map Scene |
51
+ | `data.banner` | Page hero image for the site |
52
+
53
+ An Item without `data.icon` uses its builder's configured default art. An
54
+ Actor without `data.icon` uses its compiled default art. Write `data.icon`
55
+ when the note needs a particular image. A portrait within the prose is an
56
+ image embed, for example `![[image-smith-portrait|The smith]]{size=medium}`;
57
+ it does not set a document's profile art. The
58
+ [art-slot reference](../reference/format-details.md#the-four-art-slots) gives each
59
+ slot's type and document destination.
60
+
61
+ ## Write an inline icon in prose
62
+
63
+ Declare the glyph vocabulary in `package-build.config.yaml` or a separate YAML
64
+ file named by `icons:`. The registry maps a stable content name to a font
65
+ family, glyph name, style, and accessible label:
66
+
67
+ ```yaml
68
+ icons:
69
+ families:
70
+ fontawesome: { class: fa, styles: [solid, regular], describe: Font Awesome }
71
+ icons:
72
+ warning: { style: solid, icon: triangle-exclamation, label: Warning }
73
+ ```
74
+
75
+ With one family, each icon uses it automatically. With several families, set
76
+ `defaultFamily` or give an entry `family`. The package supplies the stylesheet
77
+ and font that these declarations name; an empty registry supplies no glyphs.
78
+ The registry key uses lowercase letters, digits, and hyphens. This name is a glyph key in the local registry, not a content Address.
79
+
80
+ ```markdown
81
+ Check the :icon warning: marker before opening the gate.
82
+
83
+ The larger :icon warning:{size=2x} marks a hazardous passage.
84
+ ```
85
+
86
+ The `size` attribute is a closed list: `lg`, `xl`, `2x`, and `3x`. These values
87
+ enlarge the glyph relative to running text on the web and in the PDF. The
88
+ glyph name must be declared in this package's `icons` registry; there is no
89
+ global closed list of names. An unknown name remains visible as literal
90
+ `:icon name:` text and produces a warning at the note's position. Invalid
91
+ attributes produce errors. In HTML, a known name renders as an icon element
92
+ with an accessible label.
93
+
94
+ For a PDF, point `pdf.iconFonts` at the font file for each family used in the
95
+ book:
96
+
97
+ ```yaml
98
+ pdf:
99
+ title: The Setting Guide
100
+ document: book.yaml
101
+ iconFonts:
102
+ fontawesome: assets/fonts/fa-solid-900.ttf
103
+ ```
104
+
105
+ The book build reads glyphs from those font files. Its findings identify a
106
+ font that cannot be read or a glyph that cannot be resolved. The
107
+ [book guide](book.md) covers book selection and font configuration.
108
+
109
+ ## Check the result
110
+
111
+ Run the content lint and build the surfaces the package publishes:
112
+
113
+ ```bash
114
+ package-build lint
115
+ package-build package compile
116
+ package-build site
117
+ package-build pdf --no-compile
118
+ ```
119
+
120
+ The content index assigns addresses to image assets. The lint reports unknown
121
+ inline names and invalid art addresses. A documentation package has no packs,
122
+ so it skips `package compile`. Inspect a compiled Actor or Item's
123
+ `img`, an Actor's `prototypeToken.texture.src`, and a map's `background.src`
124
+ when checking document art. Inspect the site page and emitted Typst source for
125
+ inline icons and banners. The [command reference](../commands.md) gives the
126
+ available build and lint options.
@@ -0,0 +1,120 @@
1
+ ---
2
+ shortcode: guideslocalization
3
+ name: { full: "Localize a Foundry package" }
4
+ type: doc
5
+ subType: howto
6
+ ---
7
+
8
+ # Localize a Foundry package
9
+
10
+ A Foundry package ships translation files under `lang/` and lists them in its
11
+ generated manifest. The language commands check three different things: the
12
+ file can load in Foundry, every referenced key exists, and templates contain no
13
+ untranslated user-visible text. The [command reference](../commands.md) gives
14
+ their options and exit behavior; [configuration](../configuration.md#packagebuildlang)
15
+ defines the scan paths and exceptions.
16
+
17
+ ## Declare a language
18
+
19
+ Put a JSON object in `lang/en.json`. Flat dotted keys make the path each call
20
+ site uses visible:
21
+
22
+ ```json
23
+ {
24
+ "EXAMPLE.Actor.greeting": "Well met, {name}.",
25
+ "EXAMPLE.Skill.label": "Skill"
26
+ }
27
+ ```
28
+
29
+ Foundry's formatted localization uses single-brace placeholders, such as
30
+ `{name}`. A key cannot be both a value and a prefix: declaring both
31
+ `EXAMPLE.Skill` and `EXAMPLE.Skill.label` makes Foundry's object expansion
32
+ fail. Keep a key segment to letters, digits, underscores, and hyphens. The
33
+ `lang check` command reports invalid JSON, a non-object top level, collisions,
34
+ invalid segments, and malformed placeholders.
35
+
36
+ Include the language directory in `packageBuild.assets` and declare its file
37
+ under `packageBuild.manifest.languages`:
38
+
39
+ ```yaml
40
+ packageBuild:
41
+ assets:
42
+ - { from: lang, to: lang }
43
+ manifest:
44
+ languages:
45
+ - { lang: en, name: English, path: lang/en.json }
46
+ ```
47
+
48
+ The [manifest configuration](../configuration.md#packagebuildmanifest) covers
49
+ the rest of the manifest declaration. `package-build manifest` writes the
50
+ Foundry manifest from that configuration.
51
+
52
+ ## Check that the file loads
53
+
54
+ ```bash
55
+ package-build lang check
56
+ ```
57
+
58
+ This command reads every file matching `packageBuild.lang.sources`, which
59
+ defaults to `lang/*.json`. It fails when the glob finds nothing. A content-only
60
+ package can use this check without configuring code or template scans.
61
+
62
+ ## Check the keys used by code and templates
63
+
64
+ For packages with scripts or Handlebars templates, point the scan at the
65
+ files that reference localization keys:
66
+
67
+ ```yaml
68
+ packageBuild:
69
+ lang:
70
+ primary: lang/en.json
71
+ scripts: "src/**/*.{ts,mjs}"
72
+ templates: "templates/**/*.hbs"
73
+ ```
74
+
75
+ ```bash
76
+ package-build lang coverage
77
+ package-build lang coverage --unused
78
+ package-build lang hardcoded
79
+ ```
80
+
81
+ `coverage` compares keys in the primary file with references extracted from
82
+ scripts and templates. A referenced key that is absent fails the check. An
83
+ unreferenced declared key is advisory, because runtime code may construct its
84
+ name. `--unused` prints every advisory rather than a short preview. The scan
85
+ recognizes literal references and dynamic key shapes, including a key such as
86
+ `` `EXAMPLE.Calendar.Month.${index}.label` ``. It derives key roots from the
87
+ primary file, or uses `packageBuild.lang.keyRoots` when a root has no declared
88
+ key to derive it from.
89
+
90
+ `hardcoded` checks user-visible template text and checks that each template
91
+ compiles. It requires at least one template matching its configured glob;
92
+ `coverage` requires at least one matching script or template. A package with
93
+ no such files runs `lang check` alone.
94
+
95
+ ## Account for generated keys and intentional literals
96
+
97
+ When a repository generates localization keys by its own convention, set
98
+ `packageBuild.lang.references` to a module exporting
99
+ `references(context) -> ReferenceSet`. Its `keys`, `namespaces`, `patterns`,
100
+ and `findings` join the built-in scan before coverage analysis. This lets the
101
+ package describe dynamic references without making an unreferenced key look
102
+ used merely because it has the right prefix. The [API reference](../api.md)
103
+ defines the `ReferenceSet` fields.
104
+
105
+ Use `packageBuild.lang.retained` for a declared key prefix that is intentionally
106
+ not reached by the scan. Use `packageBuild.lang.allow` for user-visible text in
107
+ a template that is deliberately literal. Each entry includes a reason:
108
+
109
+ ```yaml
110
+ packageBuild:
111
+ lang:
112
+ retained:
113
+ - { prefix: EXAMPLE.ExternalNames, reason: Read from saved documents }
114
+ allow:
115
+ - { literal: d20, reason: Dice notation is the same in every language }
116
+ ```
117
+
118
+ Review coverage and hardcoded findings after changing a template or a
119
+ translation file. The checks are read-only; the authored JSON and templates
120
+ remain the source of the package's text.