@heroiclands/package-build 22.8.0 → 22.9.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 +14 -0
- package/content-config.mjs +0 -78
- package/docs/api.md +32 -9
- package/docs/configuration.md +1 -55
- package/docs/content-format.md +124 -11
- package/engine/calendar-notes.mjs +805 -0
- package/engine/calendars.mjs +115 -14
- package/engine/index.mjs +3 -0
- package/engine/note-dates.mjs +27 -21
- package/engine/note-vocabulary.mjs +43 -6
- package/package.json +1 -1
- package/types/content-config.d.mts +0 -10
- package/types/engine/calendar-notes.d.mts +173 -0
- package/types/engine/calendars.d.mts +108 -17
- package/types/engine/index.d.mts +1 -0
- package/types/engine/note-dates.d.mts +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @heroiclands/package-build
|
|
2
2
|
|
|
3
|
+
## 22.9.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
**Calendars are content, not configuration.** The `calendar:` block retires from `package-build.config.yaml`, and a configuration that still declares it is refused by name.
|
|
8
|
+
|
|
9
|
+
**A calendar is a note.** A `lore` note with `subType: calendar` states the months it keeps, the weekdays it names, the seasons it marks and the year-counts kept in it, and a date names one of those by writing `<calendar shortcode>.<era shortcode>`. Days that belong to no month are a short month like any other, sitting in the list where they fall in the year.
|
|
10
|
+
|
|
11
|
+
**The world states its own year.** How long the year is, how the day divides and how the moon moves are written once on the world's own `place` note and on its moon's, so no calendar restates them — and a calendar whose months do not add up to that year is refused, naming the year rather than the arithmetic.
|
|
12
|
+
|
|
13
|
+
**A body is a place.** `place` gains `celestial`, for something observed from a world rather than located on one.
|
|
14
|
+
|
|
15
|
+
**A written day is bounded by the month it names.** A five-day month accepts five days and a thirty-day month accepts thirty, in whatever order a calendar keeps them; a package that names no calendar bounds nothing.
|
|
16
|
+
|
|
3
17
|
## 22.8.0
|
|
4
18
|
|
|
5
19
|
### Minor Changes
|
package/content-config.mjs
CHANGED
|
@@ -76,7 +76,6 @@ import { EMPTY_ICON_REGISTRY, checkIconRegistry } from "./engine/content-icons.m
|
|
|
76
76
|
import { MAP_TYPES, NO_PACK, PACK_BY_TYPE } from "./engine/ids.mjs";
|
|
77
77
|
import { ACTOR_TYPES } from "./engine/subtype-registry.mjs";
|
|
78
78
|
import { NOTE_VOCABULARY } from "./engine/note-vocabulary.mjs";
|
|
79
|
-
import { UNKNOWN_DATE, parseNoteDate } from "./engine/note-dates.mjs";
|
|
80
79
|
|
|
81
80
|
/**
|
|
82
81
|
* What kind of package this is.
|
|
@@ -726,10 +725,6 @@ export function publishesContentPages(config) {
|
|
|
726
725
|
* @property {readonly string[]} packDirectories Derived: every pack directory
|
|
727
726
|
* the build produces, in compile order —
|
|
728
727
|
* each pack followed by its companions.
|
|
729
|
-
* @property {Readonly<{months: number|null, monthDays: number|null, present: string|null}>} calendar
|
|
730
|
-
* How this package's year is divided, and
|
|
731
|
-
* the date it calls the present. Every
|
|
732
|
-
* value `null` when none is declared.
|
|
733
728
|
* @property {Readonly<PackageBuildSection>} packageBuild Passed through
|
|
734
729
|
* frozen, uninterpreted. `{}` when absent.
|
|
735
730
|
* @property {Readonly<DocsSpec>} docs Frozen; `{}` when absent.
|
|
@@ -759,13 +754,11 @@ const CONFIG_KEYS = [
|
|
|
759
754
|
"relationships",
|
|
760
755
|
"systems",
|
|
761
756
|
"requiresSystem",
|
|
762
|
-
"calendar",
|
|
763
757
|
"packageBuild",
|
|
764
758
|
"publish",
|
|
765
759
|
"changelog",
|
|
766
760
|
];
|
|
767
761
|
const SYSTEM_KEYS = ["manifest", "compatibility"];
|
|
768
|
-
const CALENDAR_KEYS = ["months", "monthDays", "present"];
|
|
769
762
|
const COMPATIBILITY_KEYS = ["minimum", "verified"];
|
|
770
763
|
const DOCS_KEYS = ["itemFields"];
|
|
771
764
|
const CHANGELOG_KEYS = ["labels"];
|
|
@@ -2077,76 +2070,6 @@ function normalizeRequiresSystem(value) {
|
|
|
2077
2070
|
return requireNonEmptyString(value, "requiresSystem");
|
|
2078
2071
|
}
|
|
2079
2072
|
|
|
2080
|
-
/**
|
|
2081
|
-
* How this package's year is divided, and the date it calls the present.
|
|
2082
|
-
*
|
|
2083
|
-
* **Nothing here is about which people count from what.** A reckoning is an
|
|
2084
|
-
* era, declared by the affiliation that proclaimed it, and its epoch is the
|
|
2085
|
-
* `start` written on that note — so the only things configuration states are
|
|
2086
|
-
* the ones no note could.
|
|
2087
|
-
*
|
|
2088
|
-
* `months` and `monthDays` bound a written month and day. Both are optional,
|
|
2089
|
-
* and an absent one is checked against nothing: a toolchain that assumed a
|
|
2090
|
-
* Gregorian year here would refuse `667/2/30`, an ordinary date in a year of
|
|
2091
|
-
* twelve thirty-day months. One subdivision to a package — an era moves where
|
|
2092
|
-
* year 1 sits, it does not divide the year differently.
|
|
2093
|
-
*
|
|
2094
|
-
* `present` is the date the package computes an age against, written in the
|
|
2095
|
-
* same grammar a note's dates use, so a package whose present is best said in
|
|
2096
|
-
* an era says it that way. A package that states none computes no age, which
|
|
2097
|
-
* is the right answer for a corpus that has no present.
|
|
2098
|
-
*
|
|
2099
|
-
* @param {unknown} value - The declared `calendar:` mapping.
|
|
2100
|
-
* @returns {Readonly<{months: number|null, monthDays: number|null, present: string|null}>}
|
|
2101
|
-
* Frozen; every value `null` when absent.
|
|
2102
|
-
*/
|
|
2103
|
-
function normalizeCalendar(value) {
|
|
2104
|
-
if (value === undefined || value === null) {
|
|
2105
|
-
return Object.freeze({ months: null, monthDays: null, present: null });
|
|
2106
|
-
}
|
|
2107
|
-
if (!isPlainObject(value)) fail("calendar", "must be a mapping");
|
|
2108
|
-
const input = /** @type {Record<string, unknown>} */ (value);
|
|
2109
|
-
rejectUnknownKeys(input, CALENDAR_KEYS, "calendar.");
|
|
2110
|
-
|
|
2111
|
-
const bound = (key) => {
|
|
2112
|
-
const held = input[key];
|
|
2113
|
-
if (held === undefined || held === null) return null;
|
|
2114
|
-
if (!Number.isInteger(held) || /** @type {number} */ (held) < 1) {
|
|
2115
|
-
fail(`calendar.${key}`, "must be a positive integer");
|
|
2116
|
-
}
|
|
2117
|
-
return /** @type {number} */ (held);
|
|
2118
|
-
};
|
|
2119
|
-
const months = bound("months");
|
|
2120
|
-
const monthDays = bound("monthDays");
|
|
2121
|
-
|
|
2122
|
-
// Read through the parser the notes use rather than a second grammar, and
|
|
2123
|
-
// against this package's own bounds — a present outside the year it
|
|
2124
|
-
// declares is the one date nothing downstream would report.
|
|
2125
|
-
let present = null;
|
|
2126
|
-
if (input.present !== undefined && input.present !== null) {
|
|
2127
|
-
if (typeof input.present !== "string" && typeof input.present !== "number") {
|
|
2128
|
-
fail("calendar.present", "must be a date written as a string");
|
|
2129
|
-
}
|
|
2130
|
-
if (String(input.present).trim() === UNKNOWN_DATE) {
|
|
2131
|
-
fail(
|
|
2132
|
-
"calendar.present",
|
|
2133
|
-
`must be a date — a package that states no present computes no age, ` +
|
|
2134
|
-
`so leave the key out rather than writing \`${UNKNOWN_DATE}\``,
|
|
2135
|
-
);
|
|
2136
|
-
}
|
|
2137
|
-
const { date, findings } = parseNoteDate(input.present, {
|
|
2138
|
-
calendar: { months, monthDays },
|
|
2139
|
-
allowUnknown: false,
|
|
2140
|
-
});
|
|
2141
|
-
const refused = findings.find((finding) => finding.severity === "error");
|
|
2142
|
-
if (refused)
|
|
2143
|
-
fail("calendar.present", `is not a date this package can read — ${refused.message}`);
|
|
2144
|
-
present = /** @type {{text: string}} */ (date).text;
|
|
2145
|
-
}
|
|
2146
|
-
|
|
2147
|
-
return Object.freeze({ months, monthDays, present });
|
|
2148
|
-
}
|
|
2149
|
-
|
|
2150
2073
|
/**
|
|
2151
2074
|
* Validate the declared relationships.
|
|
2152
2075
|
*
|
|
@@ -2878,7 +2801,6 @@ export function defineConfig(config) {
|
|
|
2878
2801
|
relationships: normalizeRelationships(input.relationships),
|
|
2879
2802
|
systems,
|
|
2880
2803
|
requiresSystem,
|
|
2881
|
-
calendar: normalizeCalendar(input.calendar),
|
|
2882
2804
|
packageBuild: normalizePackageBuild(input.packageBuild),
|
|
2883
2805
|
publish: normalizePublish(input.publish),
|
|
2884
2806
|
changelog: normalizeChangelog(input.changelog),
|
package/docs/api.md
CHANGED
|
@@ -606,18 +606,23 @@ The closed registry of system ids, and the `none` that stands for no system at a
|
|
|
606
606
|
|
|
607
607
|
### `engine.calendars`
|
|
608
608
|
|
|
609
|
-
The axis every date normalises onto,
|
|
610
|
-
|
|
611
|
-
| Export | Signature
|
|
612
|
-
| ------------------- |
|
|
613
|
-
| `CANONICAL_EPOCH` | `const CANONICAL_EPOCH`
|
|
614
|
-
| `canonicalYear` | `canonicalYear(year, epoch?)`
|
|
615
|
-
| `dateSortKey` | `dateSortKey(year, month, day)`
|
|
616
|
-
| `calendarStructure` | `calendarStructure(calendar)`
|
|
609
|
+
The axis every date normalises onto, the arithmetic over a calendar's month list, and the moon. A reckoning is an **era** declared on the note about the calendar that counts those years, and its epoch is the `start` written on that row — nothing is registered in configuration. The year conversion is piecewise on the sign, because the authored numbering has no year zero while the normalised value does: authored `-1` is `0`, and `-1` and `1` are adjacent. `lunarPhase` takes a floored modulo for the same reason the conversion branches: a truncated one is right on one side of an epoch and wrong on the other.
|
|
610
|
+
|
|
611
|
+
| Export | Signature | Returns | Use it when |
|
|
612
|
+
| ------------------- | ---------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------- |
|
|
613
|
+
| `CANONICAL_EPOCH` | `const CANONICAL_EPOCH` | — | naming where the canonical axis's own year 1 sits |
|
|
614
|
+
| `canonicalYear` | `canonicalYear(year, epoch?)` | `number` — the signed year on the axis | converting a year written in one reckoning to the number everything compares on |
|
|
615
|
+
| `dateSortKey` | `dateSortKey(year, month, day)` | `number` | ordering mixed-precision dates against a single number |
|
|
616
|
+
| `calendarStructure` | `calendarStructure(calendar)` | `{months}` — `null` where unstated | reading the months a calendar keeps, before phrasing a finding |
|
|
617
|
+
| `daysInMonth` | `daysInMonth(calendar, month)` | `number` — `null` where unstated | bounding a written day against the month it names |
|
|
618
|
+
| `daysInYear` | `daysInYear(months)` | `number` | asking what a month list claims the year is |
|
|
619
|
+
| `monthStarts` | `monthStarts(months)` | `number[]` | reading the same sum as a sequence, which is what an ordering error moves |
|
|
620
|
+
| `dayOfYear` | `dayOfYear(months, month, day)` | `number` | placing a written month and day in the year |
|
|
621
|
+
| `lunarPhase` | `lunarPhase(day, epochDay, cycle)` | `number` — `0` to `cycle - 1` | asking how far into its cycle a moon is, on either side of the epoch |
|
|
617
622
|
|
|
618
623
|
### `engine.noteDates`
|
|
619
624
|
|
|
620
|
-
A date on a note is one authored string — `[~][-]YYYY[/MM[/DD]] [<
|
|
625
|
+
A date on a note is one authored string — `[~][-]YYYY[/MM[/DD]] [<calendar shortcode>.<era shortcode>]` — and every field holding one parses through a single grammar into a single record. Print `text`, order on `sort`, do arithmetic on `canonicalYear`. A bare value sits on the canonical axis and carries `era: null`; one naming an era carries the qualifier and no `canonicalYear` or `sort` keys at all until the era is resolved against the corpus. The literal `unknown` parses to the same record with the year half empty, carrying a null `sort` and a null `canonicalYear`, so nothing can order it to one end of a list.
|
|
621
626
|
|
|
622
627
|
| Export | Signature | Returns | Use it when |
|
|
623
628
|
| ----------------------- | ------------------------------- | -------------------------------------------------- | ------------------------------------------------------------- |
|
|
@@ -626,6 +631,24 @@ A date on a note is one authored string — `[~][-]YYYY[/MM[/DD]] [<affiliation
|
|
|
626
631
|
| `ERA_QUALIFIER_PATTERN` | `const ERA_QUALIFIER_PATTERN` | — | checking that a string is an era qualifier a date could carry |
|
|
627
632
|
| `parseNoteDate` | `parseNoteDate(value, options)` | `{date, findings}` — `date` is `null` when refused | reading a note's authored date, with every finding it earned |
|
|
628
633
|
|
|
634
|
+
### `engine.calendarNotes`
|
|
635
|
+
|
|
636
|
+
A calendar is a `lore` note with `subType: calendar`, declaring the months it keeps, the weekdays it names, the seasons it marks and the eras it counts years in. How long the year is, how the day divides and how the moon moves are facts about the **world**, written on its `place` note and its moon's, and no calendar may restate them — which is why the months summing to the world's year is the only arithmetic a calendar note is held to. One definition is emitted per calendar, in array shape: Foundry core prunes the keys outside its schema, and Calendaria converts the arrays to its own keyed collections.
|
|
637
|
+
|
|
638
|
+
| Export | Signature | Returns | Use it when |
|
|
639
|
+
| -------------------- | ----------------------------------------------------- | ------------------------------------------ | --------------------------------------------------------------------------- |
|
|
640
|
+
| `CALENDAR_SUBTYPE` | `const CALENDAR_SUBTYPE` | — | naming the `lore` subType whose notes are calendars |
|
|
641
|
+
| `INVARIANT_SUBTYPES` | `const INVARIANT_SUBTYPES` | — | naming the `place` subTypes a world fact may be written on |
|
|
642
|
+
| `CALENDAR_FIELDS` | `const CALENDAR_FIELDS` | — | reading the closed list of what a calendar note may declare |
|
|
643
|
+
| `INVARIANT_FIELDS` | `const INVARIANT_FIELDS` | — | reading the closed list of what a body may declare about itself |
|
|
644
|
+
| `checkCalendarNote` | `checkCalendarNote(note, opts)` | `object[]` — findings | holding a `lore` note to the family and to the year the world keeps |
|
|
645
|
+
| `checkWorldFacts` | `checkWorldFacts(note, opts)` | `object[]` — findings | holding a `place` note's world facts to one body, one year and one moon |
|
|
646
|
+
| `worldInvariants` | `worldInvariants(index)` | `{year, present, moon, body, moonName, …}` | reading the year, the present and the moon a package's own notes state |
|
|
647
|
+
| `quarterDays` | `quarterDays(daysPerYear)` | `number[]` — four days of the year | asking which days the year turns on |
|
|
648
|
+
| `compileCalendar` | `compileCalendar({note, invariants, contentPackage})` | `object` — the definition | building the one object both a core consumer and Calendaria read |
|
|
649
|
+
| `compileCalendars` | `compileCalendars(index, opts)` | `{calendars, invariants}` | building every calendar a package declares, or none where it states no year |
|
|
650
|
+
| `calendariaEnvelope` | `calendariaEnvelope(definition, opts)` | `object` — the import envelope | wrapping a definition for a hand import through Calendaria's settings |
|
|
651
|
+
|
|
629
652
|
### `engine.contentAddress`
|
|
630
653
|
|
|
631
654
|
Where a content note publishes on the web. One rule, in one place, because two builds need the same answer: the knowledgebase build renders the page, and the link manifest records the address other packages link to. Stating it twice is how a manifest comes to assert a URL that resolves at build time and 404s for the reader.
|
package/docs/configuration.md
CHANGED
|
@@ -74,14 +74,13 @@ authoring.
|
|
|
74
74
|
| [`relationships`](#relationships) | object | no; refused in a `documentation` package | `{}` |
|
|
75
75
|
| [`systems`](#systems) | object | no; refused in a `documentation` package | `{}` |
|
|
76
76
|
| [`requiresSystem`](#requiressystem) | string | no; refused in a `documentation` package | `null` |
|
|
77
|
-
| [`calendar`](#calendar) | object | no | no bounds, no present |
|
|
78
77
|
| [`packageBuild`](#the-packagebuild-section) | object | no | `{}` |
|
|
79
78
|
| [`publish`](#publish) | object | no; **required**, with `site: content`, in a `documentation` package | `{site: "homepage", address: {prefix: ""}}` |
|
|
80
79
|
| [`changelog`](#changelog) | object | no | `{labels: null}` |
|
|
81
80
|
|
|
82
81
|
Any key outside this list is refused:
|
|
83
82
|
|
|
84
|
-
> `` `<key>` is not a recognized option (expected one of: rootDir, contentPackage, foundryPackage, homepage, author, packageKind, stats, itemBuilders, paths, skipDirectories, icons, packs, docs, site, pdf, compatibility, relationships, systems, requiresSystem,
|
|
83
|
+
> `` `<key>` is not a recognized option (expected one of: rootDir, contentPackage, foundryPackage, homepage, author, packageKind, stats, itemBuilders, paths, skipDirectories, icons, packs, docs, site, pdf, compatibility, relationships, systems, requiresSystem, packageBuild, publish, changelog). ``
|
|
85
84
|
|
|
86
85
|
(`rootDir` appears in that list because it is a key `defineConfig` itself
|
|
87
86
|
accepts — an `.mjs` configuration authors it directly. A YAML configuration
|
|
@@ -1298,59 +1297,6 @@ With one, naming what it does declare instead:
|
|
|
1298
1297
|
|
|
1299
1298
|
> ``package-build config: `requiresSystem` must be a non-empty string.``
|
|
1300
1299
|
|
|
1301
|
-
### `calendar`
|
|
1302
|
-
|
|
1303
|
-
**Type:** object · **Optional** · default: no bounds and no present.
|
|
1304
|
-
|
|
1305
|
-
How this package's year is divided, and the date it calls the present:
|
|
1306
|
-
|
|
1307
|
-
```yaml
|
|
1308
|
-
calendar:
|
|
1309
|
-
months: 12
|
|
1310
|
-
monthDays: 30
|
|
1311
|
-
present: 720/6/19
|
|
1312
|
-
```
|
|
1313
|
-
|
|
1314
|
-
**Nothing here is about which people count from what.** A reckoning is an
|
|
1315
|
-
**era**, declared by the affiliation that proclaimed it, and its epoch is the
|
|
1316
|
-
`start` written on that note — so the only things this block states are the ones
|
|
1317
|
-
no note could.
|
|
1318
|
-
|
|
1319
|
-
| Key (under `calendar`) | Type | Required | Default |
|
|
1320
|
-
| ---------------------- | ---------------- | -------- | ------- |
|
|
1321
|
-
| `calendar.months` | positive integer | no | `null` |
|
|
1322
|
-
| `calendar.monthDays` | positive integer | no | `null` |
|
|
1323
|
-
| `calendar.present` | date string | no | `null` |
|
|
1324
|
-
|
|
1325
|
-
`months` and `monthDays` bound a written month and day. **Both are optional, and
|
|
1326
|
-
an absent one is checked against nothing** — a year of twelve thirty-day months
|
|
1327
|
-
is as ordinary here as a Gregorian one, so the bound is declared or it is not
|
|
1328
|
-
applied. One subdivision to a package: an era moves where year 1 sits, it does
|
|
1329
|
-
not divide the year differently.
|
|
1330
|
-
|
|
1331
|
-
`present` is the date an age is computed against. It is written in the same
|
|
1332
|
-
grammar a note's dates use — `[~][-]YYYY[/MM[/DD]] [<affiliation shortcode>.<era
|
|
1333
|
-
shortcode>]` — so a package whose present is best said in an era says it that
|
|
1334
|
-
way, and one that states no present computes no age at all.
|
|
1335
|
-
|
|
1336
|
-
An age is a function of two **dates**, not two years: subtracting years alone
|
|
1337
|
-
reds every note whose birthday falls later in the year than the present date, so
|
|
1338
|
-
the day is part of what is declared.
|
|
1339
|
-
|
|
1340
|
-
> ``package-build config: `calendar` must be a mapping.``
|
|
1341
|
-
|
|
1342
|
-
> ``package-build config: `calendar.months` must be a positive integer.``
|
|
1343
|
-
|
|
1344
|
-
> ``package-build config: `calendar.monthDays` must be a positive integer.``
|
|
1345
|
-
|
|
1346
|
-
> ``package-build config: `calendar.present` must be a date written as a string.``
|
|
1347
|
-
|
|
1348
|
-
> ``package-build config: `calendar.present` must be a date — a package that states no present computes no age, so leave the key out rather than writing `unknown`.``
|
|
1349
|
-
|
|
1350
|
-
> ``package-build config: `calendar.present` is not a date this package can read — `720/13/1` writes month 13, and `calendar.months` declares a year of 12.``
|
|
1351
|
-
|
|
1352
|
-
> ``package-build config: `calendar.<key>` is not a recognized option (expected one of: months, monthDays, present).``
|
|
1353
|
-
|
|
1354
1300
|
### `packageBuild`
|
|
1355
1301
|
|
|
1356
1302
|
Reserved for `@heroiclands/package-build`'s own packaging half — see
|
package/docs/content-format.md
CHANGED
|
@@ -3217,8 +3217,65 @@ In-world information about people, places, or concepts.
|
|
|
3217
3217
|
tournament is not a matter of time-reckoning at all — and from `culture`, which is a grouping
|
|
3218
3218
|
of people rather than an occasion they attend.
|
|
3219
3219
|
|
|
3220
|
-
| `data` property | Values
|
|
3221
|
-
| --------------- |
|
|
3220
|
+
| `data` property | Values | Description |
|
|
3221
|
+
| --------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
|
|
3222
|
+
| `epoch` | `date` | Which in-world day the world's clock reads zero on |
|
|
3223
|
+
| `months` | `{ name, abbreviation?, days }[]` | The months this calendar keeps, in order — the list sums to the world's year |
|
|
3224
|
+
| `weekdays` | `{ name, abbreviation? }[]` | The days of the week it names, in order; a calendar with no week writes none |
|
|
3225
|
+
| `seasons` | `{ name, abbreviation?, monthStart?, monthEnd?, dayStart?, dayEnd? }[]` | The seasons it marks, bounded by month or by day of year |
|
|
3226
|
+
| `eras` | `{ shortcode, name, abbreviation?, proclaimedBy?, start, end? }[]` | The year-counts kept in it, each addressed `<calendar shortcode>.<era shortcode>` |
|
|
3227
|
+
|
|
3228
|
+
#### What a calendar note declares
|
|
3229
|
+
|
|
3230
|
+
**Those five keys belong to `subType: calendar` and to no other genre of
|
|
3231
|
+
`lore`.** A note carrying one under any other subType is refused, and a calendar
|
|
3232
|
+
note that states no `months` and no `epoch` is refused too: a calendar divides
|
|
3233
|
+
the year and says where the count begins, and one that does neither is prose
|
|
3234
|
+
about time rather than a calendar.
|
|
3235
|
+
|
|
3236
|
+
```yaml
|
|
3237
|
+
type: lore
|
|
3238
|
+
subType: calendar
|
|
3239
|
+
shortcode: commoncal
|
|
3240
|
+
name:
|
|
3241
|
+
full: The Common Calendar
|
|
3242
|
+
data:
|
|
3243
|
+
epoch: 720/1/1
|
|
3244
|
+
months:
|
|
3245
|
+
- { name: Floralis, abbreviation: Flor, days: 30 }
|
|
3246
|
+
- { name: Lusenar, abbreviation: Luse, days: 31 }
|
|
3247
|
+
# … ten more, summing to the world's year
|
|
3248
|
+
seasons:
|
|
3249
|
+
- { name: Spring, monthStart: 1, monthEnd: 3 }
|
|
3250
|
+
eras:
|
|
3251
|
+
- shortcode: founding
|
|
3252
|
+
name: After the Founding
|
|
3253
|
+
abbreviation: AF
|
|
3254
|
+
proclaimedBy: vylarinmpr
|
|
3255
|
+
start: 1
|
|
3256
|
+
```
|
|
3257
|
+
|
|
3258
|
+
**Position in the list is position in the year.** Days that belong to no month
|
|
3259
|
+
are a short month like any other: a five-day festival is one entry, and where it
|
|
3260
|
+
sits in the list is where it falls in the year. There is no intercalary
|
|
3261
|
+
mechanism, because there is nothing for one to do.
|
|
3262
|
+
|
|
3263
|
+
**How long the year is, how the day divides and how the moon moves are facts
|
|
3264
|
+
about the world, not about a calendar**, so no calendar note states any of them
|
|
3265
|
+
— they are written once on the world's own `place` note and on its moon's, and
|
|
3266
|
+
every calendar is compiled against them. The one arithmetic check follows from
|
|
3267
|
+
that: `months` must sum to `year.days`, and a list that does not describes a
|
|
3268
|
+
different world rather than a different calendar.
|
|
3269
|
+
|
|
3270
|
+
**An era is a way of counting years within a calendar**, so its rows sit beside
|
|
3271
|
+
the months. Each states its own `shortcode`, unique within the note, and a date
|
|
3272
|
+
names one by writing it after the calendar's address — `3 commoncal.founding`.
|
|
3273
|
+
`proclaimedBy` is optional: a reckoning whose proclaiming body is unknown, or
|
|
3274
|
+
whose body has no note, says so by leaving it out.
|
|
3275
|
+
|
|
3276
|
+
**A calendar with no week writes no `weekdays`.** An empty list and an absent
|
|
3277
|
+
one say the same thing, and nothing downstream shows a weekday for a calendar
|
|
3278
|
+
that names none.
|
|
3222
3279
|
|
|
3223
3280
|
### type: map
|
|
3224
3281
|
|
|
@@ -3370,16 +3427,72 @@ three maps, and none of those maps needs to know it is a keep.
|
|
|
3370
3427
|
- site: A place significant by what was made or done there — ruins, monoliths, henges, works, battlefields.
|
|
3371
3428
|
- structure: A single building or habitation — halls, keeps, temples, inns, towers.
|
|
3372
3429
|
- feature: A place significant by its terrain — forests, rivers, falls, passes, fords.
|
|
3430
|
+
- celestial: A body observed from a world rather than located on one — a sun, a planet, a comet.
|
|
3431
|
+
|
|
3432
|
+
| `data` property | Values | Description |
|
|
3433
|
+
| --------------------------------- | --------------------------------------------------- | ---------------------------------------------------------------------------- |
|
|
3434
|
+
| `demonym` | `string` | What a person from this place is called — a Vylarian |
|
|
3435
|
+
| `lore` | `WikiLink[]` | Lore concerning this place — its peoples, its law, its calendar, its history |
|
|
3436
|
+
| `parents` | `WikiLink[]` | Enclosing places within which this place is located |
|
|
3437
|
+
| `population` | `number` | Approximate population (precision 2 significant digits) |
|
|
3438
|
+
| `market` | `number` | Market class, 1 to 6 — what trade a settlement supports |
|
|
3439
|
+
| `borders` | `{ to, bearing }[]` | Places sharing a frontier with this one, and where each lies from here |
|
|
3440
|
+
| `routes` | `{ to, bearing, mode, days, terrain?, leagues? }[]` | Journeys from this place's centre to another place |
|
|
3441
|
+
| `world.equatorialCircumferenceKm` | `number` | The distance round the body at its equator, in kilometres |
|
|
3442
|
+
| `world.surfaceGravityG` | `number` | Surface gravity, as a multiple of Earth's |
|
|
3443
|
+
| `world.axialTiltDegrees` | `number` | The tilt of the axis, in degrees |
|
|
3444
|
+
| `year.days` | `number` | How many days the body's year holds |
|
|
3445
|
+
| `year.hoursPerDay` | `number` | How many hours the day divides into |
|
|
3446
|
+
| `year.minutesPerHour` | `number` | How many minutes the hour divides into |
|
|
3447
|
+
| `year.secondsPerMinute` | `number` | How many seconds the minute divides into |
|
|
3448
|
+
| `present` | `date` | The day the setting stops and play begins |
|
|
3449
|
+
| `body.diameterKm` | `number` | The body's diameter, in kilometres |
|
|
3450
|
+
| `body.orbitalRadiusKm` | `number` | How far it orbits from the body it circles, in kilometres |
|
|
3451
|
+
| `body.orbit` | `string` | The orbit's shape — `circular` means the cycle never varies |
|
|
3452
|
+
| `body.inclined` | `boolean` | Whether the orbit is inclined to the plane the world orbits in |
|
|
3453
|
+
| `moon.cycle` | `number` | How many days it takes to return to the same phase |
|
|
3454
|
+
| `moon.newOn` | `date` | A day it was new, written in the reference calendar |
|
|
3455
|
+
| `moon.eclipses` | `string` | `never`, `rare`, `occasional` or `frequent` |
|
|
3456
|
+
|
|
3457
|
+
#### What a body states about itself
|
|
3458
|
+
|
|
3459
|
+
**The four groups above are the world's own facts, and they are legal on a
|
|
3460
|
+
`world` or a `celestial` note and nowhere else.** A region, a settlement, a
|
|
3461
|
+
site, a structure or a feature is somewhere _within_ a world and says nothing
|
|
3462
|
+
about the world's year.
|
|
3463
|
+
|
|
3464
|
+
```yaml
|
|
3465
|
+
# the world — type: place, subType: world
|
|
3466
|
+
data:
|
|
3467
|
+
world: { equatorialCircumferenceKm: 40000, surfaceGravityG: 1.0, axialTiltDegrees: 23.5 }
|
|
3468
|
+
year: { days: 365, hoursPerDay: 24, minutesPerHour: 60, secondsPerMinute: 60 }
|
|
3469
|
+
present: 720
|
|
3470
|
+
|
|
3471
|
+
# its moon — a note of its own, because a moon is a body and not a property
|
|
3472
|
+
data:
|
|
3473
|
+
body: { diameterKm: 3800, orbitalRadiusKm: 388600, orbit: circular, inclined: true }
|
|
3474
|
+
moon: { cycle: 30, newOn: 720/1/1, eclipses: rare }
|
|
3475
|
+
```
|
|
3373
3476
|
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3477
|
+
**`year.days` is where the year's length lives, and every calendar in the
|
|
3478
|
+
package is compiled against it.** A package whose notes state no `year` has no
|
|
3479
|
+
calendar mechanism at all: no sum is checked, and nothing is emitted. That is
|
|
3480
|
+
the right answer for a package building a setting whose world facts somebody
|
|
3481
|
+
else wrote down.
|
|
3482
|
+
|
|
3483
|
+
**One year and one moon to a package.** Two years is two settings and nothing
|
|
3484
|
+
can say which one a calendar divides; a `moon` with no `year` anywhere is
|
|
3485
|
+
refused, because a cycle counted in days has no year to be measured against.
|
|
3486
|
+
|
|
3487
|
+
**`present` is the day an age is computed against**, written in the grammar a
|
|
3488
|
+
note's dates are written in, so a setting whose present is best said in an era
|
|
3489
|
+
says it that way.
|
|
3490
|
+
|
|
3491
|
+
**`world.axialTiltDegrees`, the circumference, the gravity, the moon's diameter
|
|
3492
|
+
and its orbital radius are read by nobody.** They are there so a reader knows
|
|
3493
|
+
what kind of world this is. What the build consumes is the year, the day's
|
|
3494
|
+
divisions, the present, the moon's cycle and epoch, and whether its orbit is
|
|
3495
|
+
circular and inclined.
|
|
3383
3496
|
|
|
3384
3497
|
#### What a settlement's market supports
|
|
3385
3498
|
|