@heroiclands/package-build 22.17.2 → 22.18.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 CHANGED
@@ -1,5 +1,15 @@
1
1
  # @heroiclands/package-build
2
2
 
3
+ ## 22.18.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Beings use their subtype to choose default art.
8
+
9
+ ### Patch Changes
10
+
11
+ Being profiles identify each subject as Character, NPC, or Creature from its top-level subtype.
12
+
3
13
  ## 22.17.2
4
14
 
5
15
  ### Patch Changes
@@ -21,7 +21,7 @@ data: {}
21
21
  ---
22
22
  ```
23
23
 
24
- `name.full` is the displayed name; `name.aliases` helps search. `description` is the short page summary. `tags` hold draft state and classification. `data` holds facts about the subject shared by systems. A YAML comment is the place for an author-only note: commented values remain valid YAML but do not enter the content index or generated documents.
24
+ `name.full` is the displayed name; `name.aliases` helps search. `description` is the short page summary. `tags` hold draft state and descriptive labels. The note type's classification belongs in `subType` where it is declared. `data` holds facts about the subject shared by systems. A YAML comment is the place for an author-only note: commented values remain valid YAML but do not enter the content index or generated documents.
25
25
 
26
26
  Use `tags: [gm]` for a note intended only for the GM. It is absent from the public website and book. Foundry includes it only when its document routes to a pack with `private: true`. A note with `gm` that also creates a prose JournalEntry needs a private JournalEntry pack. Links from untagged notes to GM notes are errors; GM notes may link to one another.
27
27
 
@@ -37,4 +37,4 @@ One body describes the subject for both systems. A being's `{#appearance}` and `
37
37
 
38
38
  ## Publication and summaries
39
39
 
40
- A note infobox draws from shared `data`. A system infobox draws from the system's fields, and a mapped system with no document says “Not available.” The same authored body appears in Foundry, on the website, and in the book; presentation adapts to each medium. [Infobox details](../reference/format-details.md#the-infobox) describe field order and empty values.
40
+ A note infobox draws from shared `data`. A being profile shows its top-level `subType` as `Type: Character`, `Type: NPC`, or `Type: Creature`. A system infobox draws from the system's fields, and a mapped system with no document says “Not available.” The same authored body appears in Foundry, on the website, and in the book; presentation adapts to each medium. [Infobox details](../reference/format-details.md#the-infobox) describe field order and empty values.
@@ -58,6 +58,9 @@ it does not set a document's profile art. The
58
58
  [art-slot reference](../reference/format-details.md#the-four-art-slots) gives each
59
59
  slot's type and document destination.
60
60
 
61
+ A being's `subType` selects its compiled default art: `character` and `npc`
62
+ use person art, and `creature` uses creature art.
63
+
61
64
  ## Write an inline icon in prose
62
65
 
63
66
  Declare the glyph vocabulary in `package-build.config.yaml` or a separate YAML
@@ -101,6 +101,10 @@ column regardless.
101
101
  6. **Order is the toolchain's.** A medium renders boxes, sections and rows in
102
102
  the order given.
103
103
 
104
+ A note profile begins with `Name`. For a being with a top-level `subType`, it
105
+ follows with `Type: Character`, `Type: NPC`, or `Type: Creature`. A being with
106
+ no subtype has no `Type` row.
107
+
104
108
  **Embedded models link to documentation in an infobox.** The model Address
105
109
  continues to identify the native Item used for compilation. Its displayed link
106
110
  uses that same package, type and Shortcode under `note`, which names the
@@ -448,9 +448,8 @@ export class SystemActorCompiler extends BasePackCompiler {
448
448
  * The actor's two pieces of art, resolved, with the being default beneath
449
449
  * them.
450
450
  *
451
- * **The default follows the note's `subType`**, with tags as a compatibility
452
- * fallback for content trees that have not migrated. Both addresses belong
453
- * to the package that ships them. A tree whose index cannot answer an
451
+ * **The default follows the note's `subType`**. Both addresses belong to
452
+ * the package that ships them. A tree whose index cannot answer an
454
453
  * address — a dependency not yet fetched — falls through to the document
455
454
  * subtype's own default, so the document is never left with no art.
456
455
  *
@@ -45,7 +45,6 @@
45
45
  */
46
46
 
47
47
  import { encodeAddresses } from "./address-values.mjs";
48
- import { hasTag } from "./note-vocabulary.mjs";
49
48
  import { ASSET_SYSTEM, isAssetType } from "./asset-types.mjs";
50
49
  import { ASSETS_SEGMENT } from "./pathnames.mjs";
51
50
  import { isAssetRecord } from "./index-records.mjs";
@@ -231,7 +230,7 @@ export function artPathname(index, value, defaultType, accepts) {
231
230
  }
232
231
 
233
232
  /**
234
- * The art a being falls back to, by the kind it is tagged.
233
+ * The art a being falls back to, by its subtype.
235
234
  *
236
235
  * Both files ship in `sohl`, under `assets/icons/other/`, and both are named
237
236
  * here as addresses rather than as paths for the reason every art reference is:
@@ -239,8 +238,8 @@ export function artPathname(index, value, defaultType, accepts) {
239
238
  * package borrowing the default gets the same file the system ships.
240
239
  *
241
240
  * **Only the compiler can choose between them**, because only the compiler
242
- * reads the note's tags. A schema default is the last resort beneath this one,
243
- * and covers a world document created by hand, which no note describes.
241
+ * reads the note's subtype. A schema default is the last resort beneath this
242
+ * one, and covers a world document created by hand, which no note describes.
244
243
  *
245
244
  * @type {Readonly<Record<string, string>>}
246
245
  */
@@ -252,20 +251,16 @@ export const BEING_DEFAULT_ART = Object.freeze({
252
251
  /**
253
252
  * The default art address a being's subtype chooses, or `null`.
254
253
  *
255
- * An NPC and a character use person art; a creature uses creature art. The
256
- * tag lookup preserves defaults for package trees that have not migrated.
254
+ * An NPC and a character use person art; a creature uses creature art.
257
255
  *
258
256
  * @param {object} fm - The note's frontmatter.
259
- * @returns {string|null} The address, or `null` when no subtype or legacy tag applies.
257
+ * @returns {string|null} The address, or `null` when no subtype selects one.
260
258
  */
261
259
  export function beingDefaultArt(fm) {
262
260
  if (fm?.subType === "npc" || fm?.subType === "character") {
263
261
  return BEING_DEFAULT_ART.character;
264
262
  }
265
263
  if (fm?.subType === "creature") return BEING_DEFAULT_ART.creature;
266
- for (const [tag, address] of Object.entries(BEING_DEFAULT_ART)) {
267
- if (hasTag(fm, tag)) return address;
268
- }
269
264
  return null;
270
265
  }
271
266
 
@@ -187,6 +187,13 @@ export const NOTE_BOX_TITLE = "Profile";
187
187
  /** The note infobox's single section id. @type {string} */
188
188
  export const NOTE_SECTION_ID = "profile";
189
189
 
190
+ /** @type {Readonly<Record<string, string>>} */
191
+ const BEING_SUBTYPE_LABELS = Object.freeze({
192
+ npc: "NPC",
193
+ character: "Character",
194
+ creature: "Creature",
195
+ });
196
+
190
197
  /**
191
198
  * What a **duration pair** is called.
192
199
  *
@@ -659,8 +666,9 @@ export function linkValue(ref, resolve, hint) {
659
666
  *
660
667
  * The rows are {@link NOTE_VOCABULARY}'s declaration for the type, in its
661
668
  * order, minus what {@link NOTE_FIELD_PRESENTATION} withholds and minus every
662
- * field the note left empty. A type that declares no `data:` fields still gets
663
- * the box, because `Name` is a fact about every note.
669
+ * field the note left empty. A being's top-level `subType` adds its profile
670
+ * type. A type that declares no `data:` fields still gets the box, because
671
+ * `Name` is a fact about every note.
664
672
  *
665
673
  * @param {object} fm - The note's frontmatter.
666
674
  * @param {object} [options] - Options.
@@ -698,6 +706,9 @@ function noteBox(
698
706
  const shown = new Set();
699
707
  const name = fm?.name?.full ?? fm?.title;
700
708
  if (hasValue(name)) rows.push({ label: "Name", kind: "text", value: String(name) });
709
+ if (fm?.type === "being" && Object.hasOwn(BEING_SUBTYPE_LABELS, fm.subType)) {
710
+ rows.push({ label: "Type", kind: "text", value: BEING_SUBTYPE_LABELS[fm.subType] });
711
+ }
701
712
 
702
713
  const data = isMapping(fm?.data) ? fm.data : {};
703
714
  /** @type {Map<string, {label: string, entries: string[]}>} */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heroiclands/package-build",
3
- "version": "22.17.2",
3
+ "version": "22.18.0",
4
4
  "description": "Shared toolchain for building and shipping a HeroicLands Foundry VTT package — content compilation, manifest, localization, staging, bundle, release and deployment.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "type": "module",
@@ -230,9 +230,8 @@ export class SystemActorCompiler extends BasePackCompiler {
230
230
  * The actor's two pieces of art, resolved, with the being default beneath
231
231
  * them.
232
232
  *
233
- * **The default follows the note's `subType`**, with tags as a compatibility
234
- * fallback for content trees that have not migrated. Both addresses belong
235
- * to the package that ships them. A tree whose index cannot answer an
233
+ * **The default follows the note's `subType`**. Both addresses belong to
234
+ * the package that ships them. A tree whose index cannot answer an
236
235
  * address — a dependency not yet fetched — falls through to the document
237
236
  * subtype's own default, so the document is never left with no art.
238
237
  *
@@ -144,11 +144,10 @@ export function artPathname(index: object, value: unknown, defaultType: string,
144
144
  /**
145
145
  * The default art address a being's subtype chooses, or `null`.
146
146
  *
147
- * An NPC and a character use person art; a creature uses creature art. The
148
- * tag lookup preserves defaults for package trees that have not migrated.
147
+ * An NPC and a character use person art; a creature uses creature art.
149
148
  *
150
149
  * @param {object} fm - The note's frontmatter.
151
- * @returns {string|null} The address, or `null` when no subtype or legacy tag applies.
150
+ * @returns {string|null} The address, or `null` when no subtype selects one.
152
151
  */
153
152
  export function beingDefaultArt(fm: object): string | null;
154
153
  /**
@@ -180,7 +179,7 @@ export function unresolvedArtMessage(key: string, value: unknown): string;
180
179
  export function unacceptedArtMessage(key: string, value: unknown, type: string, accepts: Iterable<string>): string;
181
180
  export { ART_SLOTS } from "./art-slots.mjs";
182
181
  /**
183
- * The art a being falls back to, by the kind it is tagged.
182
+ * The art a being falls back to, by its subtype.
184
183
  *
185
184
  * Both files ship in `sohl`, under `assets/icons/other/`, and both are named
186
185
  * here as addresses rather than as paths for the reason every art reference is:
@@ -188,8 +187,8 @@ export { ART_SLOTS } from "./art-slots.mjs";
188
187
  * package borrowing the default gets the same file the system ships.
189
188
  *
190
189
  * **Only the compiler can choose between them**, because only the compiler
191
- * reads the note's tags. A schema default is the last resort beneath this one,
192
- * and covers a world document created by hand, which no note describes.
190
+ * reads the note's subtype. A schema default is the last resort beneath this
191
+ * one, and covers a world document created by hand, which no note describes.
193
192
  *
194
193
  * @type {Readonly<Record<string, string>>}
195
194
  */
@@ -146,8 +146,9 @@ export function linkValue(ref: unknown, resolve: (ref: unknown, hint?: object) =
146
146
  *
147
147
  * The rows are {@link NOTE_VOCABULARY}'s declaration for the type, in its
148
148
  * order, minus what {@link NOTE_FIELD_PRESENTATION} withholds and minus every
149
- * field the note left empty. A type that declares no `data:` fields still gets
150
- * the box, because `Name` is a fact about every note.
149
+ * field the note left empty. A being's top-level `subType` adds its profile
150
+ * type. A type that declares no `data:` fields still gets the box, because
151
+ * `Name` is a fact about every note.
151
152
  *
152
153
  * @param {object} fm - The note's frontmatter.
153
154
  * @param {object} [options] - Options.