@heroiclands/package-build 22.9.2 → 22.11.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 +56 -0
- package/CONTENT.md +54 -0
- package/bin/content-build.mjs +3 -1
- package/docs/api.md +11 -6
- package/docs/commands.md +1 -1
- package/docs/content-format.md +411 -201
- package/engine/actor-compiler.mjs +20 -7
- package/engine/address-fields.mjs +426 -0
- package/engine/address-values.mjs +80 -0
- package/engine/address.mjs +769 -0
- package/engine/art-fields.mjs +112 -97
- package/engine/art-slots.mjs +81 -0
- package/engine/base-compiler.mjs +61 -7
- package/engine/bundle-notes.mjs +5 -2
- package/engine/bundles.mjs +17 -10
- package/engine/content-address.mjs +23 -186
- package/engine/content-embeds.mjs +18 -4
- package/engine/content-format-check.mjs +50 -22
- package/engine/content-index.mjs +85 -43
- package/engine/content-links.mjs +105 -104
- package/engine/content-lint.mjs +11 -1
- package/engine/content-tables.mjs +9 -1
- package/engine/field-spec.mjs +21 -4
- package/engine/folder-notes.mjs +44 -15
- package/engine/foundry-entries.mjs +3 -0
- package/engine/frontmatter-lint.mjs +150 -47
- package/engine/frontmatter.mjs +55 -10
- package/engine/generate.mjs +7 -1
- package/engine/helpers.mjs +37 -9
- package/engine/holdings.mjs +41 -12
- package/engine/index-records.mjs +2 -0
- package/engine/infobox-render.mjs +2 -1
- package/engine/infobox.mjs +26 -6
- package/engine/item-compiler.mjs +5 -0
- package/engine/item-docs.mjs +7 -44
- package/engine/map-dot.mjs +2 -0
- package/engine/map-notes.mjs +7 -2
- package/engine/map-places.mjs +42 -10
- package/engine/metadata-index.mjs +60 -5
- package/engine/note-addresses.mjs +325 -0
- package/engine/note-vocabulary.mjs +140 -28
- package/engine/pdf-build.mjs +1 -1
- package/engine/pdf-toc.mjs +17 -2
- package/engine/place-relations.mjs +160 -50
- package/engine/populations.mjs +17 -9
- package/engine/reference-targets.mjs +54 -0
- package/engine/scenes.mjs +5 -2
- package/engine/shortcode-references.mjs +68 -0
- package/engine/site-build.mjs +39 -15
- package/engine/site-index.mjs +57 -75
- package/engine/sql-tables.mjs +43 -9
- package/engine/system-block.mjs +21 -0
- package/engine/system-vocabulary.mjs +46 -0
- package/engine/web-wikilinks.mjs +11 -9
- package/engine/wikilink-syntax.mjs +21 -0
- package/engine/wikilinks.mjs +92 -306
- package/hm3/actors.mjs +8 -24
- package/hm3/item-fields.mjs +15 -5
- package/package.json +1 -1
- package/sohl/infobox.mjs +111 -17
- package/sohl/item-fields.mjs +131 -41
- package/types/engine/address-fields.d.mts +95 -0
- package/types/engine/address-values.d.mts +34 -0
- package/types/engine/address.d.mts +452 -0
- package/types/engine/art-fields.d.mts +59 -53
- package/types/engine/art-slots.d.mts +40 -0
- package/types/engine/base-compiler.d.mts +24 -2
- package/types/engine/bundle-notes.d.mts +2 -2
- package/types/engine/content-address.d.mts +3 -139
- package/types/engine/content-embeds.d.mts +1 -1
- package/types/engine/content-format-check.d.mts +25 -0
- package/types/engine/content-index.d.mts +2 -2
- package/types/engine/content-links.d.mts +6 -5
- package/types/engine/field-spec.d.mts +46 -9
- package/types/engine/folder-notes.d.mts +11 -10
- package/types/engine/frontmatter-lint.d.mts +7 -97
- package/types/engine/frontmatter.d.mts +16 -1
- package/types/engine/helpers.d.mts +2 -2
- package/types/engine/infobox.d.mts +6 -0
- package/types/engine/item-docs.d.mts +1 -35
- package/types/engine/map-notes.d.mts +2 -2
- package/types/engine/note-addresses.d.mts +41 -0
- package/types/engine/note-vocabulary.d.mts +20 -3
- package/types/engine/place-relations.d.mts +12 -1
- package/types/engine/populations.d.mts +17 -2
- package/types/engine/reference-targets.d.mts +9 -0
- package/types/engine/shortcode-references.d.mts +14 -0
- package/types/engine/site-build.d.mts +3 -3
- package/types/engine/site-index.d.mts +9 -30
- package/types/engine/sql-tables.d.mts +2 -2
- package/types/engine/system-block.d.mts +17 -0
- package/types/engine/system-vocabulary.d.mts +16 -0
- package/types/engine/wikilink-syntax.d.mts +7 -0
- package/types/engine/wikilinks.d.mts +6 -109
- package/types/hm3/item-fields.d.mts +5 -0
- package/types/sohl/infobox.d.mts +6 -5
- package/types/sohl/item-fields.d.mts +8 -0
package/docs/content-format.md
CHANGED
|
@@ -94,6 +94,13 @@ column regardless.
|
|
|
94
94
|
6. **Order is the toolchain's.** A medium renders boxes, sections and rows in
|
|
95
95
|
the order given.
|
|
96
96
|
|
|
97
|
+
**Embedded models link to documentation in an infobox.** The model Address
|
|
98
|
+
continues to identify the native Item used for compilation. Its displayed link
|
|
99
|
+
uses that same package, type and Shortcode under `none`, which names the
|
|
100
|
+
corresponding documentation journal. A model with no published documentation
|
|
101
|
+
keeps its known name as plain text; the infobox does not substitute an Actor or
|
|
102
|
+
Item link.
|
|
103
|
+
|
|
97
104
|
#### What the note box holds
|
|
98
105
|
|
|
99
106
|
**The note box's fields are the type's own `data:` vocabulary, in its declared
|
|
@@ -446,17 +453,11 @@ it _there_, and a system that disagrees is not in error. A weapon weighs what
|
|
|
446
453
|
This is the same rule as `hm3.type` overriding a derived document type, applied
|
|
447
454
|
to fields: derive from the shared source, and let the system state the exception.
|
|
448
455
|
|
|
449
|
-
**A shared source and
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
shared source, and the legacy in-block key it is being swept off. Reading it
|
|
455
|
-
from the legacy position is _reported_, so the sweep has a progress signal, and
|
|
456
|
-
the note compiles to the identical document either way — the same read-both,
|
|
457
|
-
report-one shape every other retirement in this format uses. As one
|
|
458
|
-
declaration the two would let a field name only one of them, and a row this
|
|
459
|
-
table states would be reachable only by a note that had already moved.
|
|
456
|
+
**A shared source and an in-block key are separate declarations.**
|
|
457
|
+
`data.gender` is the shared source for HM3 gender; `hm3.gender` is its
|
|
458
|
+
in-block spelling, and `hm3.system.gender` is the native destination.
|
|
459
|
+
The native destination wins, followed by the in-block value and the shared
|
|
460
|
+
source. Field declarations name both source and destination explicitly.
|
|
460
461
|
|
|
461
462
|
**A field whose spelling means something else at the note level has no shared
|
|
462
463
|
source.** The fallback assumes the two vocabularies agree about what a name
|
|
@@ -465,9 +466,8 @@ publishes under, while an `affiliation` item's `system.title` is the style of
|
|
|
465
466
|
address an office carries. Where they diverge, the field declares what the
|
|
466
467
|
top-level key means instead, and the top level stops being read for it — leaving
|
|
467
468
|
`<system>.system.<field>` and the legacy in-block position, which describe the
|
|
468
|
-
document rather than the note.
|
|
469
|
-
|
|
470
|
-
levels mean the same thing by design.
|
|
469
|
+
document rather than the note. Native species is independent of the shared lore Address in `data.species`.
|
|
470
|
+
`subType` has the same meaning at both levels.
|
|
471
471
|
|
|
472
472
|
**Some of a system's fields are runtime state, and a note may not write any of
|
|
473
473
|
them.** A data model declares everything a document stores, and part of that is
|
|
@@ -485,13 +485,30 @@ the field rather than a list of names, so it covers every such field a system
|
|
|
485
485
|
adds later. The per-type tables below never list one — they are the vocabulary
|
|
486
486
|
an author writes — and each type that has any names them under its table.
|
|
487
487
|
|
|
488
|
-
**
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
488
|
+
**An `Address` becomes a `Shortcode` where the target field expects one.** SoHL
|
|
489
|
+
resolves a stored cross-reference among the items one actor holds, and packages do
|
|
490
|
+
not exist there, so the field holds a `Shortcode`. Four `affiliation` fields are
|
|
491
|
+
authored as Addresses and stored that way: `data.seat` becomes `system.seat`,
|
|
492
|
+
`data.parents` becomes `system.parents`, `data.domains` becomes `system.domain`,
|
|
493
|
+
and each authored key of `data.relations` becomes a key of `system.relations`. The
|
|
494
|
+
reduction happens at build time, and two things are errors naming the note: an
|
|
495
|
+
Address whose type the field does not accept, and two Addresses that reduce to one
|
|
496
|
+
shortcode, which the field cannot hold both of.
|
|
497
|
+
|
|
498
|
+
**A SoHL skill Address becomes a native Item UUID.** An affiliation's
|
|
499
|
+
`sohl.system.commonSkills` names skills in its own package or a declared
|
|
500
|
+
dependency. Its `system.commonSkills` contains the exact published Item UUIDs,
|
|
501
|
+
including each foreign module's own pack name. Native skill lookup uses those
|
|
502
|
+
UUIDs; the journal, website and book use documentation links for presentation.
|
|
503
|
+
|
|
504
|
+
**A `Code` suffix marks a different thing.** `system.assocSkillCode`,
|
|
505
|
+
`system.assocAffiliationCode` and `system.parentSkillCode` hold a `Shortcode` at
|
|
506
|
+
both ends — each is authored as one, under `<system>.system`, and emitted verbatim
|
|
507
|
+
— so no Address is reduced into them and none of them has a shared source. A value
|
|
508
|
+
carrying a separator is refused there by the shortcode charset rather than read as
|
|
509
|
+
an Address. `data.assocSkill`, `data.assocAffiliation` and `data.parentSkill` are
|
|
510
|
+
properties of the **page**: each is an Address naming the note an infobox row
|
|
511
|
+
links to, and none reaches a compiled document.
|
|
495
512
|
|
|
496
513
|
### The note vocabulary, and how it maps
|
|
497
514
|
|
|
@@ -575,7 +592,7 @@ destination, so the resolved value is simply dropped — the note validates, the
|
|
|
575
592
|
tree compiles, and the value goes nowhere.
|
|
576
593
|
|
|
577
594
|
**What a note writes is an address; what a document carries is a path.**
|
|
578
|
-
`data.icon` is
|
|
595
|
+
`data.icon` is an `Address` defaulting to type `icon`, so a being writes
|
|
579
596
|
`icon: anvil` and never a file name. The compiler resolves that address to the
|
|
580
597
|
file the owning package ships and writes the resulting path into `img`. The two
|
|
581
598
|
sides of this row are therefore in two different currencies, which is why the
|
|
@@ -599,17 +616,17 @@ check.
|
|
|
599
616
|
#### The four art slots
|
|
600
617
|
|
|
601
618
|
A note declares the art its document needs, and every other image in it is
|
|
602
|
-
inline. All four slots are ordinary `
|
|
619
|
+
inline. All four slots are ordinary `Address` fields declaring a default type,
|
|
603
620
|
exactly as `seat` declares `place` — a bare shortcode takes its type from the
|
|
604
621
|
declaration, and qualification climbs the same short-form ladder every other
|
|
605
622
|
link uses.
|
|
606
623
|
|
|
607
|
-
| field | default type | resolves into | on |
|
|
608
|
-
| ----------- | ------------ | ---------------------------- | ----------------------------------------- |
|
|
609
|
-
| `icon` | `icon` | `document.img` | every Actor/Item type, and embedded items |
|
|
610
|
-
| `tokenIcon` | `icon` | `prototypeToken.texture.src` | Actor types |
|
|
611
|
-
| `bgImage` | `image` | `background.src` | map types |
|
|
612
|
-
| `banner` | `image` | the site hero image | any note; not a Foundry field |
|
|
624
|
+
| field | default type | accepts | resolves into | on |
|
|
625
|
+
| ----------- | ------------ | --------------- | ---------------------------- | ----------------------------------------- |
|
|
626
|
+
| `icon` | `icon` | `icon`, `image` | `document.img` | every Actor/Item type, and embedded items |
|
|
627
|
+
| `tokenIcon` | `icon` | `icon`, `image` | `prototypeToken.texture.src` | Actor types |
|
|
628
|
+
| `bgImage` | `image` | `icon`, `image` | `background.src` | map types |
|
|
629
|
+
| `banner` | `image` | `icon`, `image` | the site hero image | any note; not a Foundry field |
|
|
613
630
|
|
|
614
631
|
All four are authored under `data:`:
|
|
615
632
|
|
|
@@ -619,16 +636,37 @@ data:
|
|
|
619
636
|
banner: packagebuild-none-image-skillbnr
|
|
620
637
|
```
|
|
621
638
|
|
|
639
|
+
**Every slot accepts a second type beyond the one it defaults to**, and the two
|
|
640
|
+
defaults pair with the same accepted set: `icon` and `tokenIcon` default to
|
|
641
|
+
`icon`, `bgImage` and `banner` default to `image`, and all four accept `icon`
|
|
642
|
+
**and** `image` regardless of which one they default to. A bare shortcode still
|
|
643
|
+
takes the slot's default — `icon: anvil` above names an `icon`, not an `image`
|
|
644
|
+
— and it is a **qualified** value, one that states its own type, that the
|
|
645
|
+
accepted set governs. `sohl-kethira-basic` writes an `icon` slot this way
|
|
646
|
+
twenty times, once per faith tradition, because a deity's profile art is a full
|
|
647
|
+
illustration rather than a game icon:
|
|
648
|
+
|
|
649
|
+
```yaml
|
|
650
|
+
data:
|
|
651
|
+
icon: image-kpagrik
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
That value is accepted because `image` is in the slot's accepted set, not
|
|
655
|
+
because it matches the default — `icon` still defaults to `icon`. `audio` is
|
|
656
|
+
refused at all four slots: a sound is not art, and a value naming one — `icon:
|
|
657
|
+
audio-thunder`, say — is an error naming the set the slot accepts, never a
|
|
658
|
+
silent fall back to the note's default art.
|
|
659
|
+
|
|
622
660
|
**Two of them are legal on _every_ note**, whatever its type. `data:` is a
|
|
623
661
|
closed container and the per-type vocabularies below are the only lists there
|
|
624
662
|
are, so a key legal everywhere is stated once here rather than repeated in
|
|
625
663
|
twenty-five tables where the one that was mistyped would be the one nobody
|
|
626
664
|
noticed:
|
|
627
665
|
|
|
628
|
-
| shared `data` property | Values
|
|
629
|
-
| ---------------------- |
|
|
630
|
-
| `icon` | `
|
|
631
|
-
| `banner` | `
|
|
666
|
+
| shared `data` property | Values | Description |
|
|
667
|
+
| ---------------------- | --------- | -------------------------------------------------------------------- |
|
|
668
|
+
| `icon` | `Address` | The document's profile art — an `icon` address, resolved into `img`. |
|
|
669
|
+
| `banner` | `Address` | The page's hero image — an `image` address. |
|
|
632
670
|
|
|
633
671
|
`icon` is legal everywhere because most types compile into a document that
|
|
634
672
|
carries one; where a type's passes emit none, the lint says so and the value is
|
|
@@ -660,7 +698,7 @@ Actor types (`being`, `vehicle`) therefore add one row:
|
|
|
660
698
|
An actor's two pieces of art are two different questions. `data.icon` is the
|
|
661
699
|
profile art — what a directory listing shows beside the name and what the sheet
|
|
662
700
|
header carries. `data.tokenIcon` is what a token on the canvas wears. Both are
|
|
663
|
-
|
|
701
|
+
addresses and both resolve the same way; only the destination differs. An Item
|
|
664
702
|
has one piece of art, so this row applies to actor types alone.
|
|
665
703
|
|
|
666
704
|
**A `data:` source is still read at the top level, for now.** `data:` did
|
|
@@ -798,7 +836,7 @@ Foundry destination: searching a built `packs-json` tree for it turns up
|
|
|
798
836
|
nothing. It reaches the generated page and the book's section plates, and
|
|
799
837
|
nothing else.
|
|
800
838
|
|
|
801
|
-
It is
|
|
839
|
+
It is an `Address` all the same, defaulting to type `image`, so a section note
|
|
802
840
|
writes `banner: skillbnr` and a note borrowing another package's plate writes
|
|
803
841
|
`banner: packagebuild-none-image-skillbnr`. The resolved record carries the
|
|
804
842
|
owning package, and each surface joins the suffix onto its own root — the site
|
|
@@ -848,7 +886,7 @@ documents in different packs and different folders:
|
|
|
848
886
|
```yaml
|
|
849
887
|
sohl:
|
|
850
888
|
pack: characteristics
|
|
851
|
-
packFolder: miscgear
|
|
889
|
+
packFolder: none-folder-miscgear
|
|
852
890
|
```
|
|
853
891
|
|
|
854
892
|
**`pack: none` compiles the note into no document.** The note is walked,
|
|
@@ -1199,10 +1237,30 @@ is where the question _which notes carry no `kbcat`?_ is answered.
|
|
|
1199
1237
|
`sql` fence is the ordinary case of _Content tables_ below, and the same
|
|
1200
1238
|
free-form value decides the headings there.
|
|
1201
1239
|
|
|
1202
|
-
###
|
|
1240
|
+
### Addresses
|
|
1203
1241
|
|
|
1204
|
-
|
|
1205
|
-
|
|
1242
|
+
Three types name one thing from another in a content tree, and they are not
|
|
1243
|
+
lengths of one another:
|
|
1244
|
+
|
|
1245
|
+
| type | written | where it is met |
|
|
1246
|
+
| ----------- | -------------------------------------------- | ----------------------------------------------------------- |
|
|
1247
|
+
| `Address` | `<package>-<system>-<note_type>-<shortcode>` | a frontmatter field, a `model:`, an art slot, a link target |
|
|
1248
|
+
| `Shortcode` | `<shortcode>` | a note's own identity, and a key a runtime resolves by |
|
|
1249
|
+
| `Wikilink` | `[[<Address>[#<anchor>]\|<text>]]` | body prose |
|
|
1250
|
+
|
|
1251
|
+
An **`Address`** is the tuple below, and it is what every field typed `Address`
|
|
1252
|
+
in the tables that follow holds. It is equally what a `model:` names, what an art
|
|
1253
|
+
slot points at and what a wikilink resolves through — so an address is the thing
|
|
1254
|
+
being named, and the brackets around one in prose are a separate matter. Three
|
|
1255
|
+
rules govern it, and the first three subsections below state them in turn: the
|
|
1256
|
+
tuple is read by position, any suffix of it may be written, and each omitted
|
|
1257
|
+
segment is supplied by a default the position declares.
|
|
1258
|
+
|
|
1259
|
+
A **`Shortcode`** is one segment, and nothing expands it — see _A shortcode is
|
|
1260
|
+
one segment, and nothing expands it_ below.
|
|
1261
|
+
|
|
1262
|
+
A **`Wikilink`** is the prose form, which contains an Address — see _Wikilinks_
|
|
1263
|
+
below.
|
|
1206
1264
|
|
|
1207
1265
|
#### The canonical address
|
|
1208
1266
|
|
|
@@ -1237,6 +1295,26 @@ the canonical address, so naming another package means naming its system too.
|
|
|
1237
1295
|
`kethira-place-tashal` is three segments, which reads as system `kethira`, and
|
|
1238
1296
|
fails.
|
|
1239
1297
|
|
|
1298
|
+
#### Authored references and generated references
|
|
1299
|
+
|
|
1300
|
+
Authored notes may use any permitted suffix. Builds leave those source bytes
|
|
1301
|
+
unchanged. Generated content indexes, SQL records, site frontmatter and generated
|
|
1302
|
+
Wikilinks contain full `package-system-type-shortcode` Addresses. For example,
|
|
1303
|
+
`data.parents: [north]` in the `thalorna` package emits
|
|
1304
|
+
`data.parents: [thalorna-none-place-north]`.
|
|
1305
|
+
|
|
1306
|
+
SQL queries compare Address-valued fields to full Addresses. A note's `shortcode`
|
|
1307
|
+
is a distinct identity component, so it is not equal to an Address stored in
|
|
1308
|
+
`data.parents`, `data.domains` or a governance rank's `lore`. Use the target's
|
|
1309
|
+
complete identity for that comparison, including its package, system and type.
|
|
1310
|
+
A stub has no published page address; its note identity still contains those
|
|
1311
|
+
components and its Shortcode.
|
|
1312
|
+
|
|
1313
|
+
The toolchain holds parsed Address properties as complete tuples internally.
|
|
1314
|
+
Address-keyed relation maps hold typed targets and standing values. Only generated
|
|
1315
|
+
output serializes these properties to Address strings. Runtime Shortcodes,
|
|
1316
|
+
Foundry UUIDs, file paths and URLs keep their own representations.
|
|
1317
|
+
|
|
1240
1318
|
#### An omitted segment defaults from where the link is written
|
|
1241
1319
|
|
|
1242
1320
|
It is **not** a wildcard and resolution is not a search. Every short form expands
|
|
@@ -1264,15 +1342,11 @@ Only a type whose own document carries a system is redirected this way. A
|
|
|
1264
1342
|
documents are core ones already at `none`, so `macro-autoattack` names the Macro
|
|
1265
1343
|
and `docmacro-autoattack` its journal — two live addresses.
|
|
1266
1344
|
|
|
1267
|
-
**
|
|
1268
|
-
system, type and shortcode alike —
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
mixed (`Clb`, `LtShoe`, `HsTunic`) while the address built from it was lowercased
|
|
1273
|
-
wholesale, so the authored name and its address disagreed. Two names differing
|
|
1274
|
-
only in case are two names nobody can tell apart, and they collapsed onto one
|
|
1275
|
-
address, one `_id` and one URL with nothing to report it.
|
|
1345
|
+
**A complete Address is lowercase throughout.** Every segment — package,
|
|
1346
|
+
system, type and shortcode alike — contains only lowercase ASCII letters and
|
|
1347
|
+
digits (`^[a-z0-9]+$`). Declared Address fields reject uppercase segments.
|
|
1348
|
+
A model reference accepts mixed-case Shortcodes and resolves their lowercase
|
|
1349
|
+
Address identity; this does not change a native embedded item's Shortcode.
|
|
1276
1350
|
|
|
1277
1351
|
**Parsing is positional counting from the right, and nothing else.** Every
|
|
1278
1352
|
segment is lowercase alphanumeric — shortcodes, **types** and **subTypes** are
|
|
@@ -1312,44 +1386,42 @@ before the vault migrated do not silently die. A slash is _unconditionally_ an
|
|
|
1312
1386
|
address separator — pipe or no pipe — so an unknown type before one is an error
|
|
1313
1387
|
rather than something to guess at.
|
|
1314
1388
|
|
|
1315
|
-
####
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
| `
|
|
1323
|
-
|
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
and a
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
The top-level `aliases:` that fed it is **retired** and refused. The nested
|
|
1338
|
-
`name.aliases:` is **not**: it is reserved for a use that does not exist yet, so
|
|
1339
|
-
it is permitted and read by nothing — no index, no resolver, no lint rule, no
|
|
1340
|
-
derived address. A note carrying one behaves exactly as one without it.
|
|
1341
|
-
|
|
1342
|
-
Requiring the label is also what makes positional parsing safe. Note names
|
|
1343
|
-
contain hyphens — `Grukar-ahk` is a name, not a `Grukar` of type `ahk` — so a
|
|
1344
|
-
target that does not parse as an address is reported as one that does not, rather
|
|
1345
|
-
than split at an arbitrary place or quietly looked up somewhere else.
|
|
1346
|
-
|
|
1347
|
-
The **empty** label is not a way of writing no label. It says _address this
|
|
1348
|
-
target, and show whatever it calls itself_ — so a note renamed later takes its new
|
|
1349
|
-
name at every citation with no link edited. `[[x|]]` is labelled; `[[x]]` is not.
|
|
1389
|
+
#### A shortcode is one segment, and nothing expands it
|
|
1390
|
+
|
|
1391
|
+
A **`Shortcode`** is a single segment of the same charset an address segment is
|
|
1392
|
+
held to, and it is a type of its own rather than the shortest `Address`. It
|
|
1393
|
+
names a thing's identity, or it is the key something resolves by where the other
|
|
1394
|
+
three segments have nothing to say:
|
|
1395
|
+
|
|
1396
|
+
| where a `Shortcode` is written | what it names |
|
|
1397
|
+
| -------------------------------------------- | ----------------------------------------------------------------------------------- |
|
|
1398
|
+
| a note's own `shortcode:` | the note's identity — the name every address of it is built from |
|
|
1399
|
+
| a custom embedded entry's `system.shortcode` | that entry's identity within the actor that holds it |
|
|
1400
|
+
| an emitted `system.relations` key | the other body this one has a standing towards |
|
|
1401
|
+
| a mystery's `skillAptitudes` keys | the skill an aptitude weighs, where the key is not a `subType:` selector |
|
|
1402
|
+
| a `Code`-suffixed system field | what the resolved address is stored as — see _The note vocabulary, and how it maps_ |
|
|
1403
|
+
|
|
1404
|
+
**The test is whether the position can take the full four-tuple.** An `Address`
|
|
1405
|
+
accepts it by definition, and the positions above cannot: a `system.relations`
|
|
1406
|
+
key is read at runtime as `relations[shortcode]`, among the items one actor
|
|
1407
|
+
carries, where packages do not exist. So nothing defaults a `Shortcode` out to
|
|
1408
|
+
four segments, and a value persisted there as an address names no standing at
|
|
1409
|
+
all.
|
|
1350
1410
|
|
|
1351
|
-
The
|
|
1352
|
-
|
|
1411
|
+
**The two halves of `relations` are two types.** The key an author writes is an
|
|
1412
|
+
`Address` — a body in another package is named in full, and one in this package
|
|
1413
|
+
by its shortcode alone — and the key the compiled Item carries is the
|
|
1414
|
+
`Shortcode` that address names. The builder performs the reduction, exactly as
|
|
1415
|
+
it does for a `Code`-suffixed field, and two authored keys reducing to one
|
|
1416
|
+
emitted key is an error naming both addresses: a shortcode is unique within one
|
|
1417
|
+
package's address space, so two packages may each declare one, and the compiled
|
|
1418
|
+
field holds one of the two.
|
|
1419
|
+
|
|
1420
|
+
**A bare shortcode in an `Address` field is not a `Shortcode`.** It is an
|
|
1421
|
+
Address written at its shortest, with the package, the system and the type all
|
|
1422
|
+
supplied by the position — the same value as the full tuple, spelled shorter.
|
|
1423
|
+
Which of the two a field holds is the field's own declaration, stated in the
|
|
1424
|
+
`Values` column of the tables below and nowhere else.
|
|
1353
1425
|
|
|
1354
1426
|
#### Every address resolves, and every build says so the same way
|
|
1355
1427
|
|
|
@@ -1388,9 +1460,9 @@ precisely because an author meets whichever build ran first. Three resolvers rea
|
|
|
1388
1460
|
one authored link; they must not describe the same mistake in three ways, and
|
|
1389
1461
|
they must never disagree about whether it is a mistake at all.
|
|
1390
1462
|
|
|
1391
|
-
#### In frontmatter,
|
|
1463
|
+
#### In frontmatter, the address is written bare
|
|
1392
1464
|
|
|
1393
|
-
|
|
1465
|
+
An **`Address` field** takes the address with no brackets:
|
|
1394
1466
|
|
|
1395
1467
|
```yaml
|
|
1396
1468
|
data:
|
|
@@ -1399,22 +1471,35 @@ data:
|
|
|
1399
1471
|
seat: tashal
|
|
1400
1472
|
```
|
|
1401
1473
|
|
|
1402
|
-
not `[[hexhodai]]`. The field is declared as
|
|
1403
|
-
|
|
1404
|
-
the reader
|
|
1474
|
+
not `[[hexhodai]]`. The field is declared as an `Address`, so the schema knows
|
|
1475
|
+
what the value is and reads it as one; brackets are a wikilink's punctuation,
|
|
1476
|
+
which the reader would have to strip before it could do anything.
|
|
1405
1477
|
|
|
1406
1478
|
A frontmatter value is parsed by the address grammar above, so a single-segment
|
|
1407
|
-
value such as `hexhodai`
|
|
1479
|
+
value such as `hexhodai` names the target by its shortcode alone, with every
|
|
1480
|
+
other segment supplied by the position. Frontmatter is structure rather than
|
|
1408
1481
|
prose: a field value is a reference something else will compile against, and it
|
|
1409
1482
|
should say exactly what it points at.
|
|
1410
1483
|
|
|
1411
|
-
**
|
|
1412
|
-
|
|
1484
|
+
**A field can supply the type.** A field naming one kind of note declares its
|
|
1485
|
+
default — `seat` a `place`, `parents` an `affiliation`, `stations` a `lore` — so
|
|
1413
1486
|
the type segment defaults from the declaration and a bare shortcode is the
|
|
1414
1487
|
ordinary case, not an abbreviation of one. That is why the examples above read
|
|
1415
1488
|
`tashal` rather than `place-tashal`: the shorter form carries the same
|
|
1416
1489
|
information, because the field already said what kind of thing it points at.
|
|
1417
1490
|
|
|
1491
|
+
The frontmatter lint checks scalar Addresses, entries in Address lists, and
|
|
1492
|
+
Address map keys at the entry's own location. Segments contain lowercase ASCII
|
|
1493
|
+
letters and digits; wikilink brackets, labels, anchors, and spaces do not belong
|
|
1494
|
+
in these fields. Optional null values and empty lists or maps express no
|
|
1495
|
+
reference. Grammar and accepted types are checked independently of whether a
|
|
1496
|
+
target exists.
|
|
1497
|
+
|
|
1498
|
+
An affiliation's `economy` accepts only `affiliation` and `lore` Addresses.
|
|
1499
|
+
Each entry states its type: `affiliation-merchants` or `lore-tanvrcrncy`.
|
|
1500
|
+
There is no default type; a bare shortcode is an error.
|
|
1501
|
+
Bundle `contents` likewise requires a type for each document.
|
|
1502
|
+
|
|
1418
1503
|
**The declaration constrains the type; it does not shorten the address.** A field
|
|
1419
1504
|
value may be written at any length, and every length is equally correct so long
|
|
1420
1505
|
as the type it names is the one the field declares. All four of these are valid
|
|
@@ -1423,14 +1508,32 @@ in a `seat` field:
|
|
|
1423
1508
|
```yaml
|
|
1424
1509
|
seat: tashal
|
|
1425
1510
|
seat: place-tashal
|
|
1426
|
-
seat:
|
|
1511
|
+
seat: none-place-tashal
|
|
1427
1512
|
seat: kethira-none-place-tashal
|
|
1428
1513
|
```
|
|
1429
1514
|
|
|
1515
|
+
Each is a **suffix** of the canonical address, which is why the third one names
|
|
1516
|
+
the system and the fourth cannot omit it — see [Shorter forms](#shorter-forms).
|
|
1517
|
+
|
|
1430
1518
|
An `affiliation-` prefix there is an **error naming the field and both types** —
|
|
1431
1519
|
never a silent widening of what the field accepts. Where a field permits more
|
|
1432
|
-
than one type
|
|
1433
|
-
|
|
1520
|
+
than one type with no default among them, a bare shortcode is refused
|
|
1521
|
+
outright — an error naming the field and the types it accepts, never a
|
|
1522
|
+
resolution across them.
|
|
1523
|
+
|
|
1524
|
+
**A position's default and its accepted set are two different declarations,
|
|
1525
|
+
and most positions are not ambiguous at all.** The paragraph above is about a
|
|
1526
|
+
position that permits more than one type with no default among them; `seat` is
|
|
1527
|
+
the plainer case, permitting exactly one. Between those sits a third shape,
|
|
1528
|
+
and it is the common one: a position that nominates one of its accepted types
|
|
1529
|
+
as the default while accepting others besides. There a bare shortcode is never
|
|
1530
|
+
a candidate to weigh — it takes the default outright, every time — and the
|
|
1531
|
+
accepted set is what a value that states its own type is checked against
|
|
1532
|
+
instead: naming any member of the set is as valid as naming the default
|
|
1533
|
+
itself, and naming a type outside it is an error against the set, never
|
|
1534
|
+
against the default alone. [The four art slots](#the-four-art-slots) are
|
|
1535
|
+
declared exactly this way — each one accepts a second type beyond the one a
|
|
1536
|
+
bare shortcode takes.
|
|
1434
1537
|
|
|
1435
1538
|
**Only the type segment defaults.** Package and system are not the field's to
|
|
1436
1539
|
supply — it has no opinion about which package holds the target — so reaching
|
|
@@ -1452,6 +1555,67 @@ Brackets belong in prose, where a link sits inside a sentence and needs marking
|
|
|
1452
1555
|
off from the words around it. A frontmatter value has nothing to be marked off
|
|
1453
1556
|
from.
|
|
1454
1557
|
|
|
1558
|
+
### Wikilinks
|
|
1559
|
+
|
|
1560
|
+
A **`Wikilink`** is how body prose names something:
|
|
1561
|
+
|
|
1562
|
+
```text
|
|
1563
|
+
[[<Address>[#<anchor>]|<text>]]
|
|
1564
|
+
```
|
|
1565
|
+
|
|
1566
|
+
The brackets, the `#<anchor>` and the `|<text>` label are the Wikilink's own.
|
|
1567
|
+
What sits inside them is an `Address` like any other — read by the same grammar,
|
|
1568
|
+
written at any of its lengths, and taking each omitted segment from where the
|
|
1569
|
+
link is written, which for body prose is this package and system `none`. So
|
|
1570
|
+
nothing about resolution belongs to the bracketed form: a wikilink and a
|
|
1571
|
+
frontmatter field ask the same question of the same value, and the findings above
|
|
1572
|
+
are the answers either of them gets.
|
|
1573
|
+
|
|
1574
|
+
The anchor is the Wikilink's, not the Address's. It names a section of the target
|
|
1575
|
+
by the slug that section's heading declares — `[[place-tashal#market|the
|
|
1576
|
+
market]]` — and one naming no section there is the `unknown-anchor` finding.
|
|
1577
|
+
Written alone, `[[#slug|Text]]` addresses a section of the page the link sits on,
|
|
1578
|
+
which is the one form carrying no address at all.
|
|
1579
|
+
|
|
1580
|
+
#### Every wikilink carries a label
|
|
1581
|
+
|
|
1582
|
+
There is one namespace, and the pipe is required:
|
|
1583
|
+
|
|
1584
|
+
| written | resolved as | displays |
|
|
1585
|
+
| ------------------- | ----------- | -------------------------- |
|
|
1586
|
+
| `[[Address\|]]` | an address | the target note's own name |
|
|
1587
|
+
| `[[Address\|Text]]` | an address | `Text` |
|
|
1588
|
+
| `[[Name]]` | nothing | a finding |
|
|
1589
|
+
|
|
1590
|
+
**A link written without a label addresses nothing**, and the correction
|
|
1591
|
+
is always the same: write `[[type-shortcode|Text]]`.
|
|
1592
|
+
|
|
1593
|
+
The bare form does not name an **alias** — a note's own display name, or one of
|
|
1594
|
+
the names it listed in `aliases:` — looked up within the citing note's type. It
|
|
1595
|
+
was measured before it was retired, and the namespace was empty in practice:
|
|
1596
|
+
across 8,305 wikilinks in three content trees, **not one** bare link resolved to
|
|
1597
|
+
a note. What the index behind it did do was fold every note's `name.full` into
|
|
1598
|
+
itself, so two notes of one type could not share a display name — a rules page
|
|
1599
|
+
and a user guide page both called "Gear" were a build failure whose every
|
|
1600
|
+
available fix moved a published URL.
|
|
1601
|
+
|
|
1602
|
+
The top-level `aliases:` that fed it is **retired** and refused. The nested
|
|
1603
|
+
`name.aliases:` is **not**: it is reserved for a use that does not exist yet, so
|
|
1604
|
+
it is permitted and read by nothing — no index, no resolver, no lint rule, no
|
|
1605
|
+
derived address. A note carrying one behaves exactly as one without it.
|
|
1606
|
+
|
|
1607
|
+
Requiring the label is also what makes positional parsing safe. Note names
|
|
1608
|
+
contain hyphens — `Grukar-ahk` is a name, not a `Grukar` of type `ahk` — so a
|
|
1609
|
+
target that does not parse as an address is reported as one that does not, rather
|
|
1610
|
+
than split at an arbitrary place or quietly looked up somewhere else.
|
|
1611
|
+
|
|
1612
|
+
The **empty** label is not a way of writing no label. It says _address this
|
|
1613
|
+
target, and show whatever it calls itself_ — so a note renamed later takes its new
|
|
1614
|
+
name at every citation with no link edited. `[[x|]]` is labelled; `[[x]]` is not.
|
|
1615
|
+
|
|
1616
|
+
It is the label that is required, not a target: the anchor-only form above
|
|
1617
|
+
carries its pipe like every other link.
|
|
1618
|
+
|
|
1455
1619
|
### Assets are types
|
|
1456
1620
|
|
|
1457
1621
|
`icon`, `image` and `audio` are types in the type vocabulary, and an address
|
|
@@ -1668,12 +1832,12 @@ type the way a field declaration does — `image`. The short-form ladder, the
|
|
|
1668
1832
|
package and system defaults, the lowercase rule, the ambiguity reporting and the
|
|
1669
1833
|
findings vocabulary all apply unchanged.
|
|
1670
1834
|
|
|
1671
|
-
| written
|
|
1672
|
-
|
|
|
1673
|
-
| `![[anvil\|]]`
|
|
1674
|
-
| `![[anvil\|An anvil]]`
|
|
1675
|
-
| `![[anvil]]`
|
|
1676
|
-
| `![[sohl-image-anvil\|Anvil]]` | qualified, reaching another package |
|
|
1835
|
+
| written | means |
|
|
1836
|
+
| ----------------------------------- | ---------------------------------------- |
|
|
1837
|
+
| `![[anvil\|]]` | decorative — the common case |
|
|
1838
|
+
| `![[anvil\|An anvil]]` | alt text where it carries meaning |
|
|
1839
|
+
| `![[anvil]]` | unlabelled, and a finding like any other |
|
|
1840
|
+
| `![[sohl-none-image-anvil\|Anvil]]` | qualified, reaching another package |
|
|
1677
1841
|
|
|
1678
1842
|
The parser distinguishes a missing label from an empty one, so _deliberately
|
|
1679
1843
|
decorative_ and _not written_ differ without an exemption.
|
|
@@ -1806,7 +1970,7 @@ so adding a type means answering the question rather than inheriting a default.
|
|
|
1806
1970
|
|
|
1807
1971
|
#### A stub is still referenceable as data
|
|
1808
1972
|
|
|
1809
|
-
`borders.to` and `routes.to` name a place by
|
|
1973
|
+
`borders.to` and `routes.to` name a place by `Address`, and those are **index
|
|
1810
1974
|
relations rather than page links**: a border with a stub on the far side is a
|
|
1811
1975
|
valid statement about the world and resolves. So does `parents` for the
|
|
1812
1976
|
containment tree and `domains` for tenure — a stub appears in its region's
|
|
@@ -2291,16 +2455,16 @@ Generates a living (or undead, or spirit) being.
|
|
|
2291
2455
|
|
|
2292
2456
|
| `data` property | Values | Description |
|
|
2293
2457
|
| --------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------ |
|
|
2294
|
-
| `tokenIcon` | `
|
|
2458
|
+
| `tokenIcon` | `Address` | What a token on the canvas wears — an `icon` address; defaults to `icon` |
|
|
2295
2459
|
| `templatePriority` | `number` | Template priority, _null_ = not a template |
|
|
2296
2460
|
| `archetypes` | `Archetype[]` | What sort of character this is. **Always an array** — `[]` where none apply; `null` is an error. |
|
|
2297
2461
|
| `occupation` | `string` | Name of the character's occupation |
|
|
2298
|
-
| `stations` | `
|
|
2299
|
-
| `lore` | `
|
|
2300
|
-
| `homes` | `
|
|
2301
|
-
| `affiliations` | `
|
|
2462
|
+
| `stations` | `Address[]` | Name of the stations the character belongs to |
|
|
2463
|
+
| `lore` | `Address[]` | Lore concerning this being — the people it is of, the standing it holds, the law it lives under |
|
|
2464
|
+
| `homes` | `Address[]` | Place the being calls home |
|
|
2465
|
+
| `affiliations` | `Address[]` | Affilliations (e.g., arcane/divine traditions, polities, etc) |
|
|
2302
2466
|
| `gender` | `male \| female \| other` | Gender of the character |
|
|
2303
|
-
| `species` | `
|
|
2467
|
+
| `species` | `Address` | Being's species (lore) |
|
|
2304
2468
|
| `born` | `YYYY/MM/DD \| unknown` | When the being was born; absent, it was never born |
|
|
2305
2469
|
| `died` | `YYYY/MM/DD \| unknown` | When the being died; absent, it is alive |
|
|
2306
2470
|
| `age` | `34 \| ~34` | Age in years, stated only to override what `born` says; `~` marks an estimate |
|
|
@@ -2539,10 +2703,15 @@ A SoHL "being" document will be created, as will an "HM3" document.
|
|
|
2539
2703
|
|
|
2540
2704
|
| shared source | → sohl | → hm3 |
|
|
2541
2705
|
| ----------------- | ------ | ------------------- |
|
|
2542
|
-
| `data.species` | NA |
|
|
2706
|
+
| `data.species` | NA | NA |
|
|
2543
2707
|
| `data.gender` | NA | `system.gender` |
|
|
2544
2708
|
| `data.occupation` | NA | `system.occupation` |
|
|
2545
2709
|
|
|
2710
|
+
`data.species` is a lore Address describing the being's species. HM3's
|
|
2711
|
+
`hm3.system.species` is independent native text; it does not inherit from
|
|
2712
|
+
`data.species`. The in-block `hm3.species` spelling is also accepted, with
|
|
2713
|
+
`hm3.system.species` taking precedence.
|
|
2714
|
+
|
|
2546
2715
|
### type: homepage
|
|
2547
2716
|
|
|
2548
2717
|
The package's front page, published at `https://www.heroiclands.org/<package>/`.
|
|
@@ -2570,10 +2739,10 @@ a card block — the homepage is a page with a body, rendered as one.
|
|
|
2570
2739
|
|
|
2571
2740
|
Represents a conveyance able to hold goods and people moving from one place to another.
|
|
2572
2741
|
|
|
2573
|
-
| `data` property | Values
|
|
2574
|
-
| ------------------ |
|
|
2575
|
-
| `tokenIcon` | `
|
|
2576
|
-
| `templatePriority` | `number`
|
|
2742
|
+
| `data` property | Values | Description |
|
|
2743
|
+
| ------------------ | --------- | ------------------------------------------------------------------------ |
|
|
2744
|
+
| `tokenIcon` | `Address` | What a token on the canvas wears — an `icon` address; defaults to `icon` |
|
|
2745
|
+
| `templatePriority` | `number` | Template priority, _null_ = not a template |
|
|
2577
2746
|
|
|
2578
2747
|
If `sohl` is present, this becomes a `vehicle` actor.
|
|
2579
2748
|
|
|
@@ -2650,12 +2819,12 @@ two is the commonest way to get a non-monarchy wrong.
|
|
|
2650
2819
|
**Rank**
|
|
2651
2820
|
Definition of a level within the organization (e.g., Priest, Layperson, Member, Gang Leader, Master, etc.)
|
|
2652
2821
|
|
|
2653
|
-
| Property | Values
|
|
2654
|
-
| ------------- |
|
|
2655
|
-
| `level` | number
|
|
2656
|
-
| `title` | string
|
|
2657
|
-
| `description` | string
|
|
2658
|
-
| `lore` | `
|
|
2822
|
+
| Property | Values | Description |
|
|
2823
|
+
| ------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
2824
|
+
| `level` | number | The ranking within the affiliation, increasing values starting with 1, 0 indicates intentional exclusion (expulsion/excommunication) |
|
|
2825
|
+
| `title` | string | Title associated with the Rank |
|
|
2826
|
+
| `description` | string | Description of the Rank |
|
|
2827
|
+
| `lore` | `Address` | The standing this rank _is_ — a `lore` note of subType `law`, shared with every other body that confers the same thing |
|
|
2659
2828
|
|
|
2660
2829
|
**A rank's `lore` is shared; its `title` is not.** A Normen kingdom calls it
|
|
2661
2830
|
`Thrall` and a Vylarian province calls it `Slave`, and they mean one standing:
|
|
@@ -2671,24 +2840,23 @@ rank names the standing, and the standing says.
|
|
|
2671
2840
|
|
|
2672
2841
|
**Standing**: aligned, unaligned, rival, nemesis
|
|
2673
2842
|
|
|
2674
|
-
| `data` property | Values
|
|
2675
|
-
| -------------------- |
|
|
2676
|
-
| `templatePriority` | `number`
|
|
2677
|
-
| `demonym` | `string`
|
|
2678
|
-
| `epithet` | `string`
|
|
2679
|
-
| `symbol` | `string`
|
|
2680
|
-
| `governance.model` | `GovernanceModel`
|
|
2681
|
-
| `governance.summary` | `string`
|
|
2682
|
-
| `governance.ranks` | `Rank[]`
|
|
2683
|
-
| `governance.offices` | `Map<name, description>`
|
|
2684
|
-
| `
|
|
2685
|
-
| `
|
|
2686
|
-
| `
|
|
2687
|
-
| `
|
|
2688
|
-
| `
|
|
2689
|
-
| `
|
|
2690
|
-
| `
|
|
2691
|
-
| `relations` | `Map<WikiLink, Standing>` | Relations with other affiliations |
|
|
2843
|
+
| `data` property | Values | Description |
|
|
2844
|
+
| -------------------- | ------------------------ | ---------------------------------------------------------------------------------------------- |
|
|
2845
|
+
| `templatePriority` | `number` | Template priority, _null_ = not a template |
|
|
2846
|
+
| `demonym` | `string` | What a member of this affiliation is called (a Vylarian) |
|
|
2847
|
+
| `epithet` | `string` | The by-name it is known by — a god's, an order's, a company's |
|
|
2848
|
+
| `symbol` | `string` | Its emblem in words: a feather atop a golden scale, a chisel carving a star |
|
|
2849
|
+
| `governance.model` | `GovernanceModel` | Type of government structure, if applicable |
|
|
2850
|
+
| `governance.summary` | `string` | summary of the governance situation |
|
|
2851
|
+
| `governance.ranks` | `Rank[]` | The ranks available to members of the affiliation |
|
|
2852
|
+
| `governance.offices` | `Map<name, description>` | Official offices in the affiliation |
|
|
2853
|
+
| `seat` | `Address` | Where the affiliation's authority sits |
|
|
2854
|
+
| `domains` | `Address[]` | Places over which this affiliation holds sway |
|
|
2855
|
+
| `population` | `number` | Number of people in the affiliation (precision 2 significant digits). |
|
|
2856
|
+
| `economy` | `Address[]` | Economic life: `affiliation` or `lore` Addresses, with an explicit type and no default |
|
|
2857
|
+
| `lore` | `Address[]` | Lore concerning it — the peoples it draws on, the god a faith venerates, its law, its calendar |
|
|
2858
|
+
| `parents` | `Address[]` | Affiliations that this affiliation is subordinate to |
|
|
2859
|
+
| `relations` | `Map<Address, Standing>` | Standing with other affiliations, keyed by the other body's Address |
|
|
2692
2860
|
|
|
2693
2861
|
**A faith tradition is not its god.** An `affiliation` of subType
|
|
2694
2862
|
`faithtradition` is a _religion_ — a practice, with an ordained priesthood, a
|
|
@@ -2763,6 +2931,27 @@ If `sohl` is present, this becomes an `affiliation` item.
|
|
|
2763
2931
|
| `data.parents` | `system.parents` | NA |
|
|
2764
2932
|
| `data.relations` | `system.relations` | NA |
|
|
2765
2933
|
|
|
2934
|
+
An affiliation writes SoHL common skills under `sohl.system.commonSkills` as a
|
|
2935
|
+
list of skill Addresses. An abbreviated value names a skill in the authoring
|
|
2936
|
+
package; a skill in the SoHL system package uses its complete Address:
|
|
2937
|
+
|
|
2938
|
+
```yaml
|
|
2939
|
+
sohl:
|
|
2940
|
+
system:
|
|
2941
|
+
commonSkills:
|
|
2942
|
+
- herb
|
|
2943
|
+
- sohl-sohl-skill-law
|
|
2944
|
+
```
|
|
2945
|
+
|
|
2946
|
+
The compiled SoHL Item stores the exact published Item UUIDs in
|
|
2947
|
+
`system.commonSkills`. An empty or absent list emits `[]`. A foreign target must
|
|
2948
|
+
come from a declared `relationships.systems` or `relationships.requires` content
|
|
2949
|
+
index. Each UUID uses the module and pack named by that target's published index;
|
|
2950
|
+
a missing skill Item or Item UUID is an error at the authored Address. The
|
|
2951
|
+
content index retains complete Addresses. Journal, web and book infoboxes link
|
|
2952
|
+
to a skill's published documentation journal when one exists and otherwise show
|
|
2953
|
+
its name as plain text.
|
|
2954
|
+
|
|
2766
2955
|
`governance` reaches no system field. Ranks and offices are the note's and the
|
|
2767
2956
|
web page's — SoHL's affiliation item has nowhere to put them, and inventing a
|
|
2768
2957
|
mapping for a field no schema declares is the drift these tables exist to catch.
|
|
@@ -3004,27 +3193,29 @@ if a `hm3` property is present, an HM3 item of type "miscgear" will be created.
|
|
|
3004
3193
|
|
|
3005
3194
|
**SkillAptitude**: either a single skill
|
|
3006
3195
|
|
|
3007
|
-
| `data` property | Values
|
|
3008
|
-
| ------------------ |
|
|
3009
|
-
| `templatePriority` | `number`
|
|
3010
|
-
| `assocSkill` | `
|
|
3011
|
-
| `assocAffiliation` | `
|
|
3012
|
-
| `skillAptitudes` | `
|
|
3013
|
-
| `level` | `number`
|
|
3014
|
-
| `charges.value` | `number`
|
|
3015
|
-
| `charges.max` | `number`
|
|
3196
|
+
| `data` property | Values | Description |
|
|
3197
|
+
| ------------------ | ---------------------------------------------------------------------------------- | -------------------------------------------------------------- |
|
|
3198
|
+
| `templatePriority` | `number` | Template priority, _null_ = not a template |
|
|
3199
|
+
| `assocSkill` | `Address` | Associated skill |
|
|
3200
|
+
| `assocAffiliation` | `Address` | Associated affiliation |
|
|
3201
|
+
| `skillAptitudes` | `Map<Shortcode, number>`, the key a skill's shortcode or `subType:<skill-subtype>` | Bonuses and penalties, per skill or per kind of skill |
|
|
3202
|
+
| `level` | `number` | Magnitude of the mystery |
|
|
3203
|
+
| `charges.value` | `number` | Current number of charges available, _null_ = charges not used |
|
|
3204
|
+
| `charges.max` | `number` | Maximum number of charges, _null_ = no maximum |
|
|
3016
3205
|
|
|
3017
3206
|
if a `sohl` property is present, a SoHL item of type "mystery" will be created.
|
|
3018
3207
|
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
|
3024
|
-
|
|
|
3025
|
-
| `
|
|
3026
|
-
| `data.
|
|
3027
|
-
| `data.
|
|
3208
|
+
`system.assocSkillCode` and `system.assocAffiliationCode` are authored under
|
|
3209
|
+
`sohl.system` as shortcodes and have no shared source; `data.assocSkill` and
|
|
3210
|
+
`data.assocAffiliation` name the same two notes as Addresses, for the page.
|
|
3211
|
+
|
|
3212
|
+
| shared source | → sohl | → hm3 |
|
|
3213
|
+
| --------------------- | ----------------------- | ----- |
|
|
3214
|
+
| `subType` | `system.subType` | NA |
|
|
3215
|
+
| `data.skillAptitudes` | `system.skillAptitudes` | NA |
|
|
3216
|
+
| `data.level` | `system.levelBase` | NA |
|
|
3217
|
+
| `data.charges.value` | `system.charges.value` | NA |
|
|
3218
|
+
| `data.charges.max` | `system.charges.max` | NA |
|
|
3028
3219
|
|
|
3029
3220
|
### type: mysticalability
|
|
3030
3221
|
|
|
@@ -3041,29 +3232,31 @@ if a `sohl` property is present, a SoHL item of type "mystery" will be created.
|
|
|
3041
3232
|
- alchemy: The preparation of substances imbued with mystical potency.
|
|
3042
3233
|
- divination: The practice of obtaining hidden knowledge or foreknowledge by mystical means.
|
|
3043
3234
|
|
|
3044
|
-
| `data` property | Values
|
|
3045
|
-
| ------------------ |
|
|
3046
|
-
| `templatePriority` | `number`
|
|
3047
|
-
| `assocSkill` | `
|
|
3048
|
-
| `assocAffiliation` | `
|
|
3049
|
-
| `masteryLevel` | `number`
|
|
3050
|
-
| `level` | `number`
|
|
3051
|
-
| `charges.value` | `number`
|
|
3052
|
-
| `charges.max` | `number`
|
|
3235
|
+
| `data` property | Values | Description |
|
|
3236
|
+
| ------------------ | --------- | -------------------------------------------------------------- |
|
|
3237
|
+
| `templatePriority` | `number` | Template priority, _null_ = not a template |
|
|
3238
|
+
| `assocSkill` | `Address` | Associated skill |
|
|
3239
|
+
| `assocAffiliation` | `Address` | Associated affiliation |
|
|
3240
|
+
| `masteryLevel` | `number` | Mastery Level |
|
|
3241
|
+
| `level` | `number` | Magnitude of the mystery |
|
|
3242
|
+
| `charges.value` | `number` | Current number of charges available, _null_ = charges not used |
|
|
3243
|
+
| `charges.max` | `number` | Maximum number of charges, _null_ = no maximum |
|
|
3053
3244
|
|
|
3054
3245
|
if a `sohl` property is present, a SoHL item of type "mysticalability" will be created.
|
|
3055
3246
|
|
|
3056
3247
|
If an `hm3` property is present, an HM3 item is created, and `hm3.type` states which — `psionic`, `spell` or `invocation`. It is **authored, not derived from `subType`**: the ten mystical-ability subtypes do not partition onto HM3's three documents (a `spiritrite`, an `alchemy` and a `divination` each answer to none of them), so a derivation would be a guess with a plausible shape. A note that omits it is an error naming the note.
|
|
3057
3248
|
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
|
3063
|
-
|
|
|
3064
|
-
| `
|
|
3065
|
-
| `data.
|
|
3066
|
-
| `data.
|
|
3249
|
+
`system.assocSkillCode` and `system.assocAffiliationCode` are authored under
|
|
3250
|
+
`sohl.system` as shortcodes and have no shared source; `data.assocSkill` and
|
|
3251
|
+
`data.assocAffiliation` name the same two notes as Addresses, for the page.
|
|
3252
|
+
|
|
3253
|
+
| shared source | → sohl | → hm3 |
|
|
3254
|
+
| -------------------- | ------------------------- | ------------- |
|
|
3255
|
+
| `subType` | `system.subType` | **see above** |
|
|
3256
|
+
| `data.masteryLevel` | `system.masteryLevelBase` | NA |
|
|
3257
|
+
| `data.level` | `system.levelBase` | NA |
|
|
3258
|
+
| `data.charges.value` | `system.charges.value` | NA |
|
|
3259
|
+
| `data.charges.max` | `system.charges.max` | NA |
|
|
3067
3260
|
|
|
3068
3261
|
### type: projectilegear
|
|
3069
3262
|
|
|
@@ -3117,11 +3310,11 @@ HM3 side while remaining distinct on the SoHL side.
|
|
|
3117
3310
|
- combat
|
|
3118
3311
|
- combattechnique
|
|
3119
3312
|
|
|
3120
|
-
| `data` property | Values
|
|
3121
|
-
| ------------------ |
|
|
3122
|
-
| `templatePriority` | `number`
|
|
3123
|
-
| `masteryLevel` | `number`
|
|
3124
|
-
| `parentSkill` | `
|
|
3313
|
+
| `data` property | Values | Description |
|
|
3314
|
+
| ------------------ | --------- | ------------------------------------------ |
|
|
3315
|
+
| `templatePriority` | `number` | Template priority, _null_ = not a template |
|
|
3316
|
+
| `masteryLevel` | `number` | Mastery Level |
|
|
3317
|
+
| `parentSkill` | `Address` | Parent skill this skill specializes |
|
|
3125
3318
|
|
|
3126
3319
|
if a `sohl` property is present, a SoHL item of type "skill" will be created.
|
|
3127
3320
|
|
|
@@ -3129,11 +3322,14 @@ If an `hm3` property is present, then an HM3 item of type "skill" will be create
|
|
|
3129
3322
|
|
|
3130
3323
|
Note: `hm3.system.type` (skill types) use the values "Craft", "Physical", "Communication", "Combat", "Magic", and "Ritual". These do not cleanly map to the `subType` values. Because of this, the `hm3.system.type` value must be specified with the appropriate value when defining HM3 skills.
|
|
3131
3324
|
|
|
3325
|
+
`system.parentSkillCode` is authored under `sohl.system` as the shortcode of the
|
|
3326
|
+
skill this one specializes, and has no shared source; `data.parentSkill` names that
|
|
3327
|
+
skill as an Address, for the page.
|
|
3328
|
+
|
|
3132
3329
|
| shared source | → sohl | → hm3 |
|
|
3133
3330
|
| ------------------- | ------------------------- | --------------------- |
|
|
3134
3331
|
| `subType` | `system.subType` | See notes above |
|
|
3135
3332
|
| `data.masteryLevel` | `system.masteryLevelBase` | `system.masteryLevel` |
|
|
3136
|
-
| `data.parentSkill` | `system.parentSkillCode` | NA |
|
|
3137
3333
|
|
|
3138
3334
|
### type: trauma
|
|
3139
3335
|
|
|
@@ -3344,7 +3540,7 @@ The `data:` fields, of which three are required:
|
|
|
3344
3540
|
|
|
3345
3541
|
| `data` property | Values | Description |
|
|
3346
3542
|
| ----------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
3347
|
-
| `bgImage` | `
|
|
3543
|
+
| `bgImage` | `Address` | **Required.** The map art — an `image` address. Becomes the level's `background.src`, what tokens stand on |
|
|
3348
3544
|
| `dimensions` | `[int, int]` | **Required.** `[width, height]` in whole pixels, the art's own size |
|
|
3349
3545
|
| `pxPerGrid` | `integer` | **Required.** Whole pixels per grid square; must match the art |
|
|
3350
3546
|
| `navName` | `string` | Short name for Foundry's scene navigation bar |
|
|
@@ -3357,7 +3553,7 @@ The `data:` fields, of which three are required:
|
|
|
3357
3553
|
| `tiles` | `Tile[]` | List of tiles, each naming its art in `image` |
|
|
3358
3554
|
| `sounds` | `Sound[]` | List of sounds, each naming its clip in `audio` |
|
|
3359
3555
|
| `regions` | `SceneRegion[]` | List of scene regions |
|
|
3360
|
-
| `place` | `
|
|
3556
|
+
| `place` | `Address` | The place this map depicts. Optional, because an encounter map depicts no named place — but that is the exception, and a map without one is a map of nowhere |
|
|
3361
3557
|
| `notes` | `NoteLocation[]` | grid coordinates of note markers mapped to anchors in this document |
|
|
3362
3558
|
|
|
3363
3559
|
Everything else a Scene holds is **derived**, not authored: padding, grid type,
|
|
@@ -3374,7 +3570,7 @@ compilation, and the server-side migration shim is version-gated on
|
|
|
3374
3570
|
single Level is synthesised from `bgImage`, `overlay`, `levelName` and
|
|
3375
3571
|
`backgroundColor`.
|
|
3376
3572
|
|
|
3377
|
-
> **`bgImage` is
|
|
3573
|
+
> **`bgImage` is an `Address` under `data:`, as every other type's artwork is.**
|
|
3378
3574
|
> Art is not system-specific — a Scene is a core Foundry document, and a second
|
|
3379
3575
|
> system would want the identical art — so the field sits under `data:` rather
|
|
3380
3576
|
> than inside a system block.
|
|
@@ -3455,8 +3651,8 @@ three maps, and none of those maps needs to know it is a keep.
|
|
|
3455
3651
|
| `data` property | Values | Description |
|
|
3456
3652
|
| --------------------------------- | --------------------------------------------------- | ---------------------------------------------------------------------------- |
|
|
3457
3653
|
| `demonym` | `string` | What a person from this place is called — a Vylarian |
|
|
3458
|
-
| `lore` | `
|
|
3459
|
-
| `parents` | `
|
|
3654
|
+
| `lore` | `Address[]` | Lore concerning this place — its peoples, its law, its calendar, its history |
|
|
3655
|
+
| `parents` | `Address[]` | Enclosing places within which this place is located |
|
|
3460
3656
|
| `population` | `number` | Approximate population (precision 2 significant digits) |
|
|
3461
3657
|
| `market` | `number` | Market class, 1 to 6 — what trade a settlement supports |
|
|
3462
3658
|
| `borders` | `{ to, bearing }[]` | Places sharing a frontier with this one, and where each lies from here |
|
|
@@ -3563,8 +3759,13 @@ data:
|
|
|
3563
3759
|
- { to: kethramir, bearing: E, mode: land, days: 30, terrain: [dunes], leagues: 90 }
|
|
3564
3760
|
```
|
|
3565
3761
|
|
|
3566
|
-
- `to` — required;
|
|
3567
|
-
|
|
3762
|
+
- `to` — required; an `Address` naming the other place. Its type segment defaults
|
|
3763
|
+
to `place` and `place` is the whole of its accepted set, so `vylar`,
|
|
3764
|
+
`place-vylar` and `thalorna-none-place-vylar` name one place and a `to` naming
|
|
3765
|
+
anything else is an error. **A bare shortcode names a place in this package**,
|
|
3766
|
+
which is what the fully qualified form is for: naming a place in a declared
|
|
3767
|
+
dependency's index, so two packages using one shortcode never answer for each
|
|
3768
|
+
other.
|
|
3568
3769
|
- `bearing` — required; where the neighbour or the destination lies from here.
|
|
3569
3770
|
- `mode` — required on a route; how the journey is travelled.
|
|
3570
3771
|
- `days` — required on a route; a marker meaning "about this, under normal
|
|
@@ -3591,6 +3792,15 @@ neighbour that states a different bearing, a different `days` or a different
|
|
|
3591
3792
|
tell which. Every `to` must resolve to a place, every value must come from its
|
|
3592
3793
|
closed set, and each finding is located at the entry that states it.
|
|
3593
3794
|
|
|
3795
|
+
**A relation that crosses a package boundary is written in full at both ends.**
|
|
3796
|
+
An omitted `<package>` segment is the package being built, in whatever note the
|
|
3797
|
+
value is read from — a note of this package's own, or a record a consumer fetched
|
|
3798
|
+
out of a dependency's index — so a short `to` names a different place in a
|
|
3799
|
+
different build. Only the fully qualified form names one place everywhere, which
|
|
3800
|
+
is why the long form is not optional for a border or a route between packages,
|
|
3801
|
+
and why a short `to` in a fetched record names the package being built rather
|
|
3802
|
+
than the package that wrote it.
|
|
3803
|
+
|
|
3594
3804
|
| `bearing` value | where the other place lies |
|
|
3595
3805
|
| --------------- | -------------------------- |
|
|
3596
3806
|
| `N` | north |
|
|
@@ -3719,7 +3929,7 @@ because they were true of something else, and each removal has a home to go to.
|
|
|
3719
3929
|
|
|
3720
3930
|
**`languages` is a fact about a polity.** A place's languages change when its
|
|
3721
3931
|
ruler changes, which is what makes them the ruler's property — and
|
|
3722
|
-
`
|
|
3932
|
+
`sohl.system.commonSkills` holds them. The authored corpus agrees: of 206
|
|
3723
3933
|
places carrying `languages`, 190 were settlements and 16 were regions, and not one
|
|
3724
3934
|
was a site, a structure or a feature. A ruin has no language.
|
|
3725
3935
|
|
|
@@ -3749,14 +3959,14 @@ Content prepared to be played — a situation with its cast, places, and possibl
|
|
|
3749
3959
|
|
|
3750
3960
|
| `data` property | Values | Description |
|
|
3751
3961
|
| ------------------ | -------------------------------------------- | ------------------------------------------------------------------------------ |
|
|
3752
|
-
| `parents` | `
|
|
3753
|
-
| `locations` | `
|
|
3754
|
-
| `cast` | `
|
|
3755
|
-
| `factions` | `
|
|
3756
|
-
| `follows` | `
|
|
3962
|
+
| `parents` | `Address[]` | List of parent scenarios of this scenario (campaigns, etc.) |
|
|
3963
|
+
| `locations` | `Address[]` | List of locations associated with this scenario |
|
|
3964
|
+
| `cast` | `Address[]` | individuals associated with this scenario |
|
|
3965
|
+
| `factions` | `Address[]` | Affiliations associated with this scenario |
|
|
3966
|
+
| `follows` | `Address[]` | Prerequisite scenarios that should be completed before beginning this scenario |
|
|
3757
3967
|
| `status` | `draft \| playtested \| published` | Playability status of this scenario |
|
|
3758
3968
|
| `party.size` | `solo \| small \| standard \| large \| host` | Suggested party size (solo=1, small=2-3, standard=4-6, large=6-7, host=7+) |
|
|
3759
|
-
| `party.archetypes` | `Archetype`
|
|
3969
|
+
| `party.archetypes` | `Archetype[]` | Archetypes of characters suitable for completion |
|
|
3760
3970
|
|
|
3761
3971
|
### type: doc
|
|
3762
3972
|
|
|
@@ -3859,9 +4069,9 @@ authors none takes Foundry's own `icons/svg/dice-target.svg`.
|
|
|
3859
4069
|
|
|
3860
4070
|
A bundle of notes to be taken as a single unit — an `Adventure` in Foundry VTT.
|
|
3861
4071
|
|
|
3862
|
-
| `data` property | Values
|
|
3863
|
-
| --------------- |
|
|
3864
|
-
| `contents` | `
|
|
4072
|
+
| `data` property | Values | Description |
|
|
4073
|
+
| --------------- | ----------- | ------------------------------------------------------ |
|
|
4074
|
+
| `contents` | `Address[]` | The documents the Adventure holds; `[]` when unstated. |
|
|
3865
4075
|
|
|
3866
4076
|
```yaml
|
|
3867
4077
|
---
|
|
@@ -3944,10 +4154,10 @@ data:
|
|
|
3944
4154
|
---
|
|
3945
4155
|
```
|
|
3946
4156
|
|
|
3947
|
-
| `data` property | Values
|
|
3948
|
-
| --------------- |
|
|
3949
|
-
| `parent` | `
|
|
3950
|
-
| `color` | `"#RRGGBB"`, a string
|
|
4157
|
+
| `data` property | Values | Description |
|
|
4158
|
+
| --------------- | ----------------------------------------- | ------------------------------------------------------------------------------ |
|
|
4159
|
+
| `parent` | `Address`, or a map of them keyed by pack | The folder this one sits in — one address, or one per pack. Unset at the root. |
|
|
4160
|
+
| `color` | `"#RRGGBB"`, a string | The folder's colour. Unset for Foundry's default. |
|
|
3951
4161
|
|
|
3952
4162
|
A folder is addressed `<package>-none-folder-<shortcode>` — **`none`**, because a
|
|
3953
4163
|
`Folder` is a core Foundry document like a `JournalEntry` or a `Scene`, not a
|