@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.
- package/CHANGELOG.md +103 -0
- package/README.md +39 -678
- package/bin/{content-build.mjs → content-commands.mjs} +197 -118
- package/bin/package-build.mjs +303 -42
- package/bin/report.mjs +1 -1
- package/ci/ci-docker.mjs +6 -3
- package/ci/ci-steps.mjs +6 -4
- package/ci/content-format-reference.mjs +106 -0
- package/config.mjs +22 -2
- package/content-config.mjs +74 -134
- package/docs/api.md +294 -234
- package/docs/authoring/assets.md +31 -0
- package/docs/authoring/dates-and-calendars.md +33 -0
- package/docs/authoring/first-note.md +48 -0
- package/docs/authoring/frontmatter.md +40 -0
- package/docs/authoring/links-and-markup.md +137 -0
- package/docs/commands.md +631 -162
- package/docs/configuration.md +176 -140
- package/docs/content-format.md +50 -4229
- package/docs/design.md +32 -0
- package/docs/diagnostics.md +29 -22
- package/docs/getting-started.md +21 -877
- package/docs/guides/book.md +153 -0
- package/docs/guides/e2e.md +143 -0
- package/docs/guides/icons.md +126 -0
- package/docs/guides/localization.md +120 -0
- package/docs/guides/module-project.md +915 -0
- package/docs/guides/packs.md +167 -0
- package/docs/guides/reference-pages.md +148 -0
- package/docs/guides/release-and-deploy.md +114 -0
- package/docs/guides/site.md +152 -0
- package/docs/guides/system-project.md +45 -0
- package/docs/index.md +16 -0
- package/docs/project-setup.md +54 -35
- package/docs/reference/format-details.md +4420 -0
- package/docs/reference/note-types.md +531 -0
- package/engine/address-render.mjs +26 -0
- package/engine/address.mjs +3 -20
- package/engine/anchors.mjs +15 -6
- package/engine/asset-bindings.mjs +6 -2
- package/engine/base-compiler.mjs +47 -11
- package/engine/being-measurements.mjs +70 -0
- package/engine/calendar-artifacts.mjs +1 -1
- package/engine/calendar-choice.mjs +32 -0
- package/engine/calendar-human.mjs +71 -0
- package/engine/calendar-notes.mjs +41 -3
- package/engine/calendars.mjs +8 -1
- package/engine/changelog-lint.mjs +2 -2
- package/engine/code-fences.mjs +23 -97
- package/engine/compile-corpus.mjs +6 -7
- package/engine/content-admonitions.mjs +114 -0
- package/engine/content-captions.mjs +181 -0
- package/engine/content-embeds.mjs +2 -2
- package/engine/content-footnotes.mjs +34 -0
- package/engine/content-format-check.mjs +2 -2
- package/engine/content-format.mjs +127 -73
- package/engine/content-format.yaml +745 -0
- package/engine/content-html.mjs +1 -1
- package/engine/content-icons.mjs +45 -92
- package/engine/content-images.mjs +22 -74
- package/engine/content-index.mjs +12 -3
- package/engine/content-links.mjs +21 -26
- package/engine/content-lint.mjs +1 -5
- package/engine/content-secrets.mjs +3 -1
- package/engine/content-tables.mjs +47 -1257
- package/engine/culture-choice.mjs +32 -0
- package/engine/date-conversion.mjs +47 -0
- package/engine/declaration-check.mjs +87 -0
- package/engine/docs-checks.mjs +140 -0
- package/engine/documentation-links.mjs +31 -0
- package/engine/exported-scene.mjs +1 -1
- package/engine/extension-attributes.mjs +74 -0
- package/engine/field-reference.mjs +1 -1
- package/engine/field-spec.mjs +4 -0
- package/engine/foreign-catalog.mjs +5 -5
- package/engine/format-generated.mjs +15 -0
- package/engine/foundry-entries.mjs +3 -1
- package/engine/frontmatter-lint.mjs +5 -1
- package/engine/frontmatter.mjs +10 -0
- package/engine/generate.mjs +2 -2
- package/engine/helpers.mjs +71 -117
- package/engine/homepage.mjs +2 -3
- package/engine/index-records.mjs +1 -0
- package/engine/index.mjs +18 -3
- package/engine/infobox-registry.mjs +3 -1
- package/engine/infobox.mjs +38 -20
- package/engine/item-compiler.mjs +10 -8
- package/engine/item-docs.mjs +7 -6
- package/engine/itinerary-scenes.mjs +4 -2
- package/engine/journals.mjs +51 -10
- package/engine/macros.mjs +1 -1
- package/engine/map-build.mjs +1 -1
- package/engine/map-dot.mjs +1 -1
- package/engine/map-raster.mjs +4 -2
- package/engine/markdown-expressions.mjs +117 -0
- package/engine/metadata-index.mjs +7 -3
- package/engine/note-addresses.mjs +1 -0
- package/engine/note-dates.mjs +283 -61
- package/engine/note-package.mjs +5 -25
- package/engine/note-state.mjs +6 -2
- package/engine/note-vocabulary.mjs +74 -19
- package/engine/number-words.mjs +75 -0
- package/engine/office-holders.mjs +188 -0
- package/engine/pack-config.mjs +2 -15
- package/engine/pack-router.mjs +24 -5
- package/engine/packages.mjs +3 -2
- package/engine/pathnames.mjs +21 -24
- package/engine/pdf-build.mjs +217 -55
- package/engine/pdf-fonts.mjs +2 -2
- package/engine/pdf-images.mjs +82 -0
- package/engine/pdf-render.mjs +174 -22
- package/engine/populations.mjs +3 -2
- package/engine/project-init.mjs +499 -0
- package/engine/prose-config.mjs +1 -1
- package/engine/prose-lint.mjs +7 -6
- package/engine/readability-lint.mjs +86 -0
- package/engine/reckoning-markers.mjs +205 -93
- package/engine/scenes.mjs +5 -2
- package/engine/schema-check.mjs +3 -3
- package/engine/site-build.mjs +87 -37
- package/engine/site-config.mjs +8 -8
- package/engine/site-index.mjs +4 -0
- package/engine/site-maps.mjs +1 -1
- package/engine/site-preview.mjs +19 -8
- package/engine/social-ties.mjs +5 -1
- package/engine/sql-tables.mjs +92 -22
- package/engine/web-wikilinks.mjs +15 -31
- package/engine/wikilink-syntax.mjs +4 -1
- package/engine/wikilinks.mjs +12 -14
- package/hm3/item-fields.mjs +1 -1
- package/hm3/items.mjs +12 -45
- package/index.mjs +2 -14
- package/manifest.mjs +31 -4
- package/markdownlint-config.mjs +1 -1
- package/package.json +32 -11
- package/prettier-config.mjs +1 -1
- package/sohl/being-info.mjs +3 -145
- package/sohl/index.mjs +1 -1
- package/sohl/infobox.mjs +2 -1
- package/sohl/item-builders.mjs +3 -27
- package/sohl/item-fields.mjs +61 -22
- package/sohl/kb-passes.mjs +2 -2
- package/sohl/note-schemas.mjs +0 -8
- package/stage.mjs +19 -0
- package/types/config.d.mts +12 -3
- package/types/content-config.d.mts +15 -81
- package/types/engine/address-render.d.mts +13 -0
- package/types/engine/address.d.mts +2 -11
- package/types/engine/anchors.d.mts +3 -4
- package/types/engine/asset-bindings.d.mts +9 -2
- package/types/engine/base-compiler.d.mts +1 -2
- package/types/engine/being-measurements.d.mts +16 -0
- package/types/engine/calendar-choice.d.mts +14 -0
- package/types/engine/calendar-human.d.mts +4 -0
- package/types/engine/calendar-notes.d.mts +2 -0
- package/types/engine/calendars.d.mts +5 -3
- package/types/engine/code-fences.d.mts +6 -72
- package/types/engine/compile-corpus.d.mts +1 -3
- package/types/engine/content-admonitions.d.mts +24 -0
- package/types/engine/content-captions.d.mts +45 -0
- package/types/engine/content-footnotes.d.mts +10 -0
- package/types/engine/content-format-check.d.mts +17 -4
- package/types/engine/content-format.d.mts +24 -11
- package/types/engine/content-icons.d.mts +14 -23
- package/types/engine/content-images.d.mts +2 -2
- package/types/engine/content-index.d.mts +9 -2
- package/types/engine/content-links.d.mts +3 -5
- package/types/engine/content-tables.d.mts +11 -140
- package/types/engine/culture-choice.d.mts +14 -0
- package/types/engine/date-conversion.d.mts +4 -0
- package/types/engine/declaration-check.d.mts +24 -0
- package/types/engine/docs-checks.d.mts +28 -0
- package/types/engine/documentation-links.d.mts +7 -0
- package/types/engine/exported-scene.d.mts +6 -2
- package/types/engine/extension-attributes.d.mts +14 -0
- package/types/engine/field-spec.d.mts +9 -0
- package/types/engine/format-generated.d.mts +7 -0
- package/types/engine/frontmatter.d.mts +14 -4
- package/types/engine/generate.d.mts +1 -1
- package/types/engine/helpers.d.mts +37 -92
- package/types/engine/homepage.d.mts +2 -3
- package/types/engine/index.d.mts +5 -0
- package/types/engine/infobox-registry.d.mts +3 -1
- package/types/engine/infobox.d.mts +17 -6
- package/types/engine/item-compiler.d.mts +4 -4
- package/types/engine/item-docs.d.mts +4 -3
- package/types/engine/journals.d.mts +10 -7
- package/types/engine/map-graphviz.d.mts +1 -1
- package/types/engine/markdown-expressions.d.mts +17 -0
- package/types/engine/note-dates.d.mts +47 -1
- package/types/engine/note-package.d.mts +3 -19
- package/types/engine/note-state.d.mts +2 -1
- package/types/engine/note-vocabulary.d.mts +9 -0
- package/types/engine/number-words.d.mts +4 -0
- package/types/engine/office-holders.d.mts +14 -0
- package/types/engine/pack-config.d.mts +1 -1
- package/types/engine/packages.d.mts +3 -2
- package/types/engine/pdf-images.d.mts +38 -0
- package/types/engine/populations.d.mts +2 -2
- package/types/engine/project-init.d.mts +17 -0
- package/types/engine/prose-config.d.mts +1 -1
- package/types/engine/prose-lint.d.mts +3 -2
- package/types/engine/readability-lint.d.mts +22 -0
- package/types/engine/reckoning-markers.d.mts +4 -2
- package/types/engine/schema-check.d.mts +3 -3
- package/types/engine/site-build.d.mts +38 -28
- package/types/engine/site-config.d.mts +2 -2
- package/types/engine/site-index.d.mts +4 -0
- package/types/engine/site-preview.d.mts +1 -1
- package/types/engine/social-ties.d.mts +8 -2
- package/types/engine/sql-tables.d.mts +13 -2
- package/types/engine/web-wikilinks.d.mts +2 -1
- package/types/engine/wikilinks.d.mts +7 -1
- package/types/hm3/items.d.mts +5 -6
- package/types/labels.d.mts +40 -0
- package/types/manifest.d.mts +3 -3
- package/types/sohl/actors.d.mts +2 -2
- package/types/sohl/being-info.d.mts +3 -43
- package/types/sohl/index.d.mts +1 -1
- package/types/sohl/infobox.d.mts +5 -2
- package/types/sohl/item-fields.d.mts +4 -13
- package/types/stage.d.mts +9 -0
- 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.
|