diff --git a/README.md b/README.md index ecd202f..531adae 100644 --- a/README.md +++ b/README.md @@ -180,7 +180,7 @@ The build runs all three guards before it writes anything: ``` -check-rules: OK — 87 rules, 16 files scanned, 3 aliases + 41 constant sets checked, 275 formulas verified +check-rules: OK — 87 rules, 17 files scanned, 3 aliases + 41 constant sets checked, 275 formulas verified check-kits: OK — 25 roles, 10 trades, 218 catalogue items, every kit key resolves, every posting can use what it carries, every loadout distinct check-lang: OK — en.json, 927 keys, no leaf/branch collisions check-behaviour: OK — 38 behavioural tests diff --git a/docs/REVIEW_LOG.md b/docs/REVIEW_LOG.md index 5fd2a31..fa5154d 100644 --- a/docs/REVIEW_LOG.md +++ b/docs/REVIEW_LOG.md @@ -5070,3 +5070,63 @@ species bonus." Checked afterwards that every localisation key still referenced by the engine or a template exists; the six apparent misses are Handlebars concatenation prefixes rather than lookups. + +## The player primer, and the journals finally look like the game + +Ten pages a player reads before session one, in their own compendium at OBSERVER +ownership: nine of setting and one cheat sheet. Plus the branding that all four +journals in the system had been going without. + +**The voice was the first thing to fix.** The draft called the organisation "the +Bureau" throughout. Everything else in the game — twelve rules pages, the starter, 927 +localisation strings — calls it *the department* or *the agency*. One name, and it is +not Bureau. + +**Where the draft was thin, it got filled rather than padded.** The character section +now carries the seven principles as an ordered list a player can actually work from; +"what it costs" gets the real Coherence band table rather than a paragraph describing +one, and says what the anchor in the kit is for; and the recruitment page separates +*what continuity means in practice* from *what it is not*, because "it is not a +superpower" is the single most important sentence for a new player and it was buried. + +**The cheat sheet's numbers are computed, not typed.** Hit points, Major Wound, damage +modifier, the defence penalties, the range ladder and the Coherence bands all come out +of `rules.mjs` and `lang/en.json` at build time. A hand-typed cheat sheet would have +been the sixth time this project shipped a number that disagreed with the code — and it +would have been the one the players were holding. It closes on six questions new +players actually ask, including "am I going to die?" answered honestly. + +### R-250. The design tokens were never on `:root` + +The journals rendered as Foundry's default parchment, and chasing why took four wrong +guesses that are worth recording, because each one looked right. + +1. **The hook name.** v14's journal sheet is an ApplicationV2: the hook is + `renderJournalEntrySheet`, not `renderJournalSheet`. +2. **`element` is the node.** On AppV2 it is the root element, not a jQuery wrapper. + Reaching for `[0]` silently returns the first *child* — which is how the first + version appeared to work, put the class on a header button, and changed nothing. +3. **The page container.** There is no `.journal-page-content` in v14. The prose sits + directly inside `article.journal-entry-page`. +4. **And then the real one.** With the class on the right element and the selector + matching, `font-size`, `line-height` and `padding` from my rule were all applying — + and every colour was not. `--rb-deep` resolved to nothing. The palette is declared + on `.ringbrp-sheet, .ringbrp-chat, .ringbrp-window` and **never on `:root`**, so a + journal carrying a new class inherited no tokens at all. Every `var()` silently + became nothing, which CSS treats as "unset" rather than as an error. + +The tell was that the *numeric* properties from the same rule worked while the coloured +ones did not. A rule that half-applies is not a specificity problem, and I spent three +attempts treating it as one — including bumping the system version on a cache theory +that was wrong. + +Adding `.ringbrp-journal` to the token block fixed all of it at once. + +**Now branded:** the primer, the generated rulebook, the starter's GM text and its +handouts. Scoped by a flag, so another module's journals in the same world are +untouched. The contents rail is the yellow-on-navy of the sheet tabs, read-aloud gets a +spot-colour margin rule, diagrams are monospaced in a bordered block, and the cheat +sheet is a grid of cards so it can be skimmed under pressure rather than read. + +Version bumped to 0.9.0 — which, incidentally, is what makes Foundry re-fetch the +stylesheet for anyone updating. diff --git a/package.json b/package.json index 5a06a4a..7e3276f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ringbrp", - "version": "0.8.0", - "description": "The Custodians \u2014 a Basic Roleplaying game of crossings, for Foundry VTT", + "version": "0.9.0", + "description": "The Custodians — a Basic Roleplaying game of crossings, for Foundry VTT", "main": "ringbrp.mjs", "scripts": { "build": "node tools/build-packs.mjs && node tools/update-readme.mjs", diff --git a/packs/armour/LOG b/packs/armour/LOG index b150376..64122b1 100644 --- a/packs/armour/LOG +++ b/packs/armour/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.855265 1754e3000 Recovering log #3 -2026/08/12-00:06:16.855669 1754e3000 Level-0 table #5: started -2026/08/12-00:06:16.855836 1754e3000 Level-0 table #5: 4591 bytes OK -2026/08/12-00:06:16.856081 1754e3000 Delete type=0 #3 -2026/08/12-00:06:16.856115 1754e3000 Delete type=3 #2 +2026/08/12-10:15:09.925114 17200b000 Recovering log #3 +2026/08/12-10:15:09.925148 17200b000 Level-0 table #5: started +2026/08/12-10:15:09.925283 17200b000 Level-0 table #5: 4591 bytes OK +2026/08/12-10:15:09.925570 17200b000 Delete type=0 #3 +2026/08/12-10:15:09.925615 17200b000 Delete type=3 #2 diff --git a/packs/armour/LOG.old b/packs/armour/LOG.old index 76d96d2..359bf9b 100644 --- a/packs/armour/LOG.old +++ b/packs/armour/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.690846 171b57000 Delete type=3 #1 +2026/08/12-10:14:43.782384 173eef000 Delete type=3 #1 diff --git a/packs/expedition/LOG b/packs/expedition/LOG index 2720361..d6d3173 100644 --- a/packs/expedition/LOG +++ b/packs/expedition/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.873912 1754e3000 Recovering log #3 -2026/08/12-00:06:16.874024 1754e3000 Level-0 table #5: started -2026/08/12-00:06:16.874152 1754e3000 Level-0 table #5: 4129 bytes OK -2026/08/12-00:06:16.874423 1754e3000 Delete type=0 #3 -2026/08/12-00:06:16.874466 1754e3000 Delete type=3 #2 +2026/08/12-10:15:09.941304 173023000 Recovering log #3 +2026/08/12-10:15:09.941329 173023000 Level-0 table #5: started +2026/08/12-10:15:09.941465 173023000 Level-0 table #5: 4129 bytes OK +2026/08/12-10:15:09.941748 173023000 Delete type=0 #3 +2026/08/12-10:15:09.941781 173023000 Delete type=3 #2 diff --git a/packs/expedition/LOG.old b/packs/expedition/LOG.old index 0d1e32e..c189aa3 100644 --- a/packs/expedition/LOG.old +++ b/packs/expedition/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.732633 17134b000 Delete type=3 #1 +2026/08/12-10:14:43.827491 1726cb000 Delete type=3 #1 diff --git a/packs/gear/LOG b/packs/gear/LOG index d212fb2..90124f5 100644 --- a/packs/gear/LOG +++ b/packs/gear/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.857059 174cd7000 Recovering log #3 -2026/08/12-00:06:16.857573 174cd7000 Level-0 table #5: started -2026/08/12-00:06:16.857903 174cd7000 Level-0 table #5: 31614 bytes OK -2026/08/12-00:06:16.858145 174cd7000 Delete type=0 #3 -2026/08/12-00:06:16.858196 174cd7000 Delete type=3 #2 +2026/08/12-10:15:09.926306 173023000 Recovering log #3 +2026/08/12-10:15:09.926421 173023000 Level-0 table #5: started +2026/08/12-10:15:09.926814 173023000 Level-0 table #5: 31614 bytes OK +2026/08/12-10:15:09.927163 173023000 Delete type=0 #3 +2026/08/12-10:15:09.927207 173023000 Delete type=3 #2 diff --git a/packs/gear/LOG.old b/packs/gear/LOG.old index c8def97..c88d7d9 100644 --- a/packs/gear/LOG.old +++ b/packs/gear/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.692998 170b3f000 Delete type=3 #1 +2026/08/12-10:14:43.784415 173eef000 Delete type=3 #1 diff --git a/packs/npcs/LOG b/packs/npcs/LOG index b7730b8..2b7df33 100644 --- a/packs/npcs/LOG +++ b/packs/npcs/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.840426 174cd7000 Recovering log #3 -2026/08/12-00:06:16.842114 174cd7000 Level-0 table #5: started -2026/08/12-00:06:16.843749 174cd7000 Level-0 table #5: 225945 bytes OK -2026/08/12-00:06:16.844107 174cd7000 Delete type=0 #3 -2026/08/12-00:06:16.844201 174cd7000 Delete type=3 #2 +2026/08/12-10:15:09.914246 173023000 Recovering log #3 +2026/08/12-10:15:09.915233 173023000 Level-0 table #5: started +2026/08/12-10:15:09.916771 173023000 Level-0 table #5: 225945 bytes OK +2026/08/12-10:15:09.917162 173023000 Delete type=0 #3 +2026/08/12-10:15:09.917219 173023000 Delete type=3 #2 diff --git a/packs/npcs/LOG.old b/packs/npcs/LOG.old index 0fc6a18..1b98b67 100644 --- a/packs/npcs/LOG.old +++ b/packs/npcs/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.708940 170b3f000 Delete type=3 #1 +2026/08/12-10:14:43.800859 1726cb000 Delete type=3 #1 diff --git a/packs/powers/LOG b/packs/powers/LOG index 5981400..9cbef14 100644 --- a/packs/powers/LOG +++ b/packs/powers/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.850448 1754e3000 Recovering log #3 -2026/08/12-00:06:16.850937 1754e3000 Level-0 table #5: started -2026/08/12-00:06:16.851096 1754e3000 Level-0 table #5: 3295 bytes OK -2026/08/12-00:06:16.851406 1754e3000 Delete type=0 #3 -2026/08/12-00:06:16.851447 1754e3000 Delete type=3 #2 +2026/08/12-10:15:09.922245 17200b000 Recovering log #3 +2026/08/12-10:15:09.922265 17200b000 Level-0 table #5: started +2026/08/12-10:15:09.922421 17200b000 Level-0 table #5: 3295 bytes OK +2026/08/12-10:15:09.922681 17200b000 Delete type=0 #3 +2026/08/12-10:15:09.922713 17200b000 Delete type=3 #2 diff --git a/packs/powers/LOG.old b/packs/powers/LOG.old index 2107343..ced2e69 100644 --- a/packs/powers/LOG.old +++ b/packs/powers/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.725493 171b57000 Delete type=3 #1 +2026/08/12-10:14:43.821081 1726cb000 Delete type=3 #1 diff --git a/packs/pregens/LOG b/packs/pregens/LOG index 50fb7ad..42ee2a9 100644 --- a/packs/pregens/LOG +++ b/packs/pregens/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.836787 174cd7000 Recovering log #3 -2026/08/12-00:06:16.837779 174cd7000 Level-0 table #5: started -2026/08/12-00:06:16.838453 174cd7000 Level-0 table #5: 58792 bytes OK -2026/08/12-00:06:16.838760 174cd7000 Delete type=0 #3 -2026/08/12-00:06:16.838812 174cd7000 Delete type=3 #2 +2026/08/12-10:15:09.911544 173023000 Recovering log #3 +2026/08/12-10:15:09.911759 173023000 Level-0 table #5: started +2026/08/12-10:15:09.912426 173023000 Level-0 table #5: 58792 bytes OK +2026/08/12-10:15:09.912801 173023000 Delete type=0 #3 +2026/08/12-10:15:09.912846 173023000 Delete type=3 #2 diff --git a/packs/pregens/LOG.old b/packs/pregens/LOG.old index 967ffa0..2c2de79 100644 --- a/packs/pregens/LOG.old +++ b/packs/pregens/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.699399 170b3f000 Delete type=3 #1 +2026/08/12-10:14:43.791044 173eef000 Delete type=3 #1 diff --git a/packs/primer/000005.ldb b/packs/primer/000005.ldb new file mode 100644 index 0000000..669e7b1 Binary files /dev/null and b/packs/primer/000005.ldb differ diff --git a/packs/primer/000006.log b/packs/primer/000006.log new file mode 100644 index 0000000..daa37bb Binary files /dev/null and b/packs/primer/000006.log differ diff --git a/packs/primer/CURRENT b/packs/primer/CURRENT new file mode 100644 index 0000000..cacca75 --- /dev/null +++ b/packs/primer/CURRENT @@ -0,0 +1 @@ +MANIFEST-000004 diff --git a/packs/primer/LOG b/packs/primer/LOG new file mode 100644 index 0000000..a50ac4a --- /dev/null +++ b/packs/primer/LOG @@ -0,0 +1,5 @@ +2026/08/12-10:15:09.929600 17382f000 Recovering log #3 +2026/08/12-10:15:09.929643 17382f000 Level-0 table #5: started +2026/08/12-10:15:09.929903 17382f000 Level-0 table #5: 21613 bytes OK +2026/08/12-10:15:09.930174 17382f000 Delete type=0 #3 +2026/08/12-10:15:09.930216 17382f000 Delete type=3 #2 diff --git a/packs/primer/LOG.old b/packs/primer/LOG.old new file mode 100644 index 0000000..6de6949 --- /dev/null +++ b/packs/primer/LOG.old @@ -0,0 +1 @@ +2026/08/12-10:14:43.817678 1726cb000 Delete type=3 #1 diff --git a/packs/primer/MANIFEST-000004 b/packs/primer/MANIFEST-000004 new file mode 100644 index 0000000..2ce4ec2 Binary files /dev/null and b/packs/primer/MANIFEST-000004 differ diff --git a/packs/rules/000005.ldb b/packs/rules/000005.ldb index e88a6f7..c8f9c7d 100644 Binary files a/packs/rules/000005.ldb and b/packs/rules/000005.ldb differ diff --git a/packs/rules/000006.log b/packs/rules/000006.log index 2d0501f..7b08998 100644 Binary files a/packs/rules/000006.log and b/packs/rules/000006.log differ diff --git a/packs/rules/LOG b/packs/rules/LOG index cb74d2a..e4d9c12 100644 --- a/packs/rules/LOG +++ b/packs/rules/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.861054 174cd7000 Recovering log #3 -2026/08/12-00:06:16.861635 174cd7000 Level-0 table #5: started -2026/08/12-00:06:16.861956 174cd7000 Level-0 table #5: 33473 bytes OK -2026/08/12-00:06:16.862206 174cd7000 Delete type=0 #3 -2026/08/12-00:06:16.862237 174cd7000 Delete type=3 #2 +2026/08/12-10:15:09.930884 17200b000 Recovering log #3 +2026/08/12-10:15:09.930957 17200b000 Level-0 table #5: started +2026/08/12-10:15:09.931274 17200b000 Level-0 table #5: 33484 bytes OK +2026/08/12-10:15:09.931485 17200b000 Delete type=0 #3 +2026/08/12-10:15:09.931513 17200b000 Delete type=3 #2 diff --git a/packs/rules/LOG.old b/packs/rules/LOG.old index 3d704dc..9568411 100644 --- a/packs/rules/LOG.old +++ b/packs/rules/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.729349 17134b000 Delete type=3 #1 +2026/08/12-10:14:43.825718 1726cb000 Delete type=3 #1 diff --git a/packs/rules/MANIFEST-000004 b/packs/rules/MANIFEST-000004 index f38776b..15f0607 100644 Binary files a/packs/rules/MANIFEST-000004 and b/packs/rules/MANIFEST-000004 differ diff --git a/packs/skills/LOG b/packs/skills/LOG index 7db8a54..d732c09 100644 --- a/packs/skills/LOG +++ b/packs/skills/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.846928 1744cb000 Recovering log #3 -2026/08/12-00:06:16.847099 1744cb000 Level-0 table #5: started -2026/08/12-00:06:16.847302 1744cb000 Level-0 table #5: 7590 bytes OK -2026/08/12-00:06:16.847547 1744cb000 Delete type=0 #3 -2026/08/12-00:06:16.847579 1744cb000 Delete type=3 #2 +2026/08/12-10:15:09.920048 17200b000 Recovering log #3 +2026/08/12-10:15:09.920101 17200b000 Level-0 table #5: started +2026/08/12-10:15:09.920292 17200b000 Level-0 table #5: 7590 bytes OK +2026/08/12-10:15:09.920533 17200b000 Delete type=0 #3 +2026/08/12-10:15:09.920569 17200b000 Delete type=3 #2 diff --git a/packs/skills/LOG.old b/packs/skills/LOG.old index 98129dd..a1432a0 100644 --- a/packs/skills/LOG.old +++ b/packs/skills/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.685076 170b3f000 Delete type=3 #1 +2026/08/12-10:14:43.775951 172ed7000 Delete type=3 #1 diff --git a/packs/slice/000005.ldb b/packs/slice/000005.ldb index 4851c77..ac4df01 100644 Binary files a/packs/slice/000005.ldb and b/packs/slice/000005.ldb differ diff --git a/packs/slice/000006.log b/packs/slice/000006.log index c7d9b16..c25ac75 100644 Binary files a/packs/slice/000006.log and b/packs/slice/000006.log differ diff --git a/packs/slice/LOG b/packs/slice/LOG index f2b4b09..671c6e4 100644 --- a/packs/slice/LOG +++ b/packs/slice/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.870148 1744cb000 Recovering log #3 -2026/08/12-00:06:16.870587 1744cb000 Level-0 table #5: started -2026/08/12-00:06:16.870864 1744cb000 Level-0 table #5: 16892 bytes OK -2026/08/12-00:06:16.871211 1744cb000 Delete type=0 #3 -2026/08/12-00:06:16.871266 1744cb000 Delete type=3 #2 +2026/08/12-10:15:09.938481 172817000 Recovering log #3 +2026/08/12-10:15:09.938536 172817000 Level-0 table #5: started +2026/08/12-10:15:09.938839 172817000 Level-0 table #5: 16902 bytes OK +2026/08/12-10:15:09.939182 172817000 Delete type=0 #3 +2026/08/12-10:15:09.939235 172817000 Delete type=3 #2 diff --git a/packs/slice/LOG.old b/packs/slice/LOG.old index e1cb79d..e24df3f 100644 --- a/packs/slice/LOG.old +++ b/packs/slice/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.723650 170b3f000 Delete type=3 #1 +2026/08/12-10:14:43.819552 1736e3000 Delete type=3 #1 diff --git a/packs/slice/MANIFEST-000004 b/packs/slice/MANIFEST-000004 index 0552c3a..0966a50 100644 Binary files a/packs/slice/MANIFEST-000004 and b/packs/slice/MANIFEST-000004 differ diff --git a/packs/starter/000005.ldb b/packs/starter/000005.ldb index 5c410fe..c0f9d9b 100644 Binary files a/packs/starter/000005.ldb and b/packs/starter/000005.ldb differ diff --git a/packs/starter/000006.log b/packs/starter/000006.log index 6c9b64b..aaf167c 100644 Binary files a/packs/starter/000006.log and b/packs/starter/000006.log differ diff --git a/packs/starter/LOG b/packs/starter/LOG index fa2bb45..23a3421 100644 --- a/packs/starter/LOG +++ b/packs/starter/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.864877 1744cb000 Recovering log #3 -2026/08/12-00:06:16.865947 1744cb000 Level-0 table #5: started -2026/08/12-00:06:16.866787 1744cb000 Level-0 table #5: 82274 bytes OK -2026/08/12-00:06:16.867102 1744cb000 Delete type=0 #3 -2026/08/12-00:06:16.867176 1744cb000 Delete type=3 #2 +2026/08/12-10:15:09.933901 172817000 Recovering log #3 +2026/08/12-10:15:09.934300 172817000 Level-0 table #5: started +2026/08/12-10:15:09.935025 172817000 Level-0 table #5: 82299 bytes OK +2026/08/12-10:15:09.935279 172817000 Delete type=0 #3 +2026/08/12-10:15:09.935312 172817000 Delete type=3 #2 diff --git a/packs/starter/LOG.old b/packs/starter/LOG.old index 4e5bd27..b8e48b1 100644 --- a/packs/starter/LOG.old +++ b/packs/starter/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.720012 170333000 Delete type=3 #1 +2026/08/12-10:14:43.811578 1736e3000 Delete type=3 #1 diff --git a/packs/starter/MANIFEST-000004 b/packs/starter/MANIFEST-000004 index b8a7dce..87687fc 100644 Binary files a/packs/starter/MANIFEST-000004 and b/packs/starter/MANIFEST-000004 differ diff --git a/packs/tables/LOG b/packs/tables/LOG index 8c1f830..c2e3d86 100644 --- a/packs/tables/LOG +++ b/packs/tables/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.872191 173cbf000 Recovering log #3 -2026/08/12-00:06:16.872466 173cbf000 Level-0 table #5: started -2026/08/12-00:06:16.872601 173cbf000 Level-0 table #5: 3739 bytes OK -2026/08/12-00:06:16.872838 173cbf000 Delete type=0 #3 -2026/08/12-00:06:16.872870 173cbf000 Delete type=3 #2 +2026/08/12-10:15:09.940141 17200b000 Recovering log #3 +2026/08/12-10:15:09.940161 17200b000 Level-0 table #5: started +2026/08/12-10:15:09.940281 17200b000 Level-0 table #5: 3739 bytes OK +2026/08/12-10:15:09.940565 17200b000 Delete type=0 #3 +2026/08/12-10:15:09.940598 17200b000 Delete type=3 #2 diff --git a/packs/tables/LOG.old b/packs/tables/LOG.old index e0e34e8..869365b 100644 --- a/packs/tables/LOG.old +++ b/packs/tables/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.713770 17134b000 Delete type=3 #1 +2026/08/12-10:14:43.805210 1726cb000 Delete type=3 #1 diff --git a/packs/talents/LOG b/packs/talents/LOG index 25ac20e..1889c72 100644 --- a/packs/talents/LOG +++ b/packs/talents/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.848619 173cbf000 Recovering log #3 -2026/08/12-00:06:16.848765 173cbf000 Level-0 table #5: started -2026/08/12-00:06:16.848948 173cbf000 Level-0 table #5: 5770 bytes OK -2026/08/12-00:06:16.849247 173cbf000 Delete type=0 #3 -2026/08/12-00:06:16.849307 173cbf000 Delete type=3 #2 +2026/08/12-10:15:09.921227 173023000 Recovering log #3 +2026/08/12-10:15:09.921256 173023000 Level-0 table #5: started +2026/08/12-10:15:09.921405 173023000 Level-0 table #5: 5770 bytes OK +2026/08/12-10:15:09.921672 173023000 Delete type=0 #3 +2026/08/12-10:15:09.921715 173023000 Delete type=3 #2 diff --git a/packs/talents/LOG.old b/packs/talents/LOG.old index fb93ea3..7ba195c 100644 --- a/packs/talents/LOG.old +++ b/packs/talents/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.687537 17134b000 Delete type=3 #1 +2026/08/12-10:14:43.779038 173eef000 Delete type=3 #1 diff --git a/packs/vehicles/LOG b/packs/vehicles/LOG index 0565ef4..247f394 100644 --- a/packs/vehicles/LOG +++ b/packs/vehicles/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.859394 1754e3000 Recovering log #3 -2026/08/12-00:06:16.859688 1754e3000 Level-0 table #5: started -2026/08/12-00:06:16.859874 1754e3000 Level-0 table #5: 6939 bytes OK -2026/08/12-00:06:16.860159 1754e3000 Delete type=0 #3 -2026/08/12-00:06:16.860190 1754e3000 Delete type=3 #2 +2026/08/12-10:15:09.928207 172817000 Recovering log #3 +2026/08/12-10:15:09.928248 172817000 Level-0 table #5: started +2026/08/12-10:15:09.928429 172817000 Level-0 table #5: 6939 bytes OK +2026/08/12-10:15:09.928761 172817000 Delete type=0 #3 +2026/08/12-10:15:09.928810 172817000 Delete type=3 #2 diff --git a/packs/vehicles/LOG.old b/packs/vehicles/LOG.old index 876771f..8fbd016 100644 --- a/packs/vehicles/LOG.old +++ b/packs/vehicles/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.694993 17134b000 Delete type=3 #1 +2026/08/12-10:14:43.786318 173eef000 Delete type=3 #1 diff --git a/packs/weapons/LOG b/packs/weapons/LOG index 7557d5c..7b5de13 100644 --- a/packs/weapons/LOG +++ b/packs/weapons/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.852833 173cbf000 Recovering log #3 -2026/08/12-00:06:16.853536 173cbf000 Level-0 table #5: started -2026/08/12-00:06:16.853822 173cbf000 Level-0 table #5: 14767 bytes OK -2026/08/12-00:06:16.854096 173cbf000 Delete type=0 #3 -2026/08/12-00:06:16.854134 173cbf000 Delete type=3 #2 +2026/08/12-10:15:09.923574 17382f000 Recovering log #3 +2026/08/12-10:15:09.923739 17382f000 Level-0 table #5: started +2026/08/12-10:15:09.924049 17382f000 Level-0 table #5: 14767 bytes OK +2026/08/12-10:15:09.924348 17382f000 Delete type=0 #3 +2026/08/12-10:15:09.924394 17382f000 Delete type=3 #2 diff --git a/packs/weapons/LOG.old b/packs/weapons/LOG.old index e8dcdd7..2d24c97 100644 --- a/packs/weapons/LOG.old +++ b/packs/weapons/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.689273 17134b000 Delete type=3 #1 +2026/08/12-10:14:43.780736 1726cb000 Delete type=3 #1 diff --git a/ringbrp.mjs b/ringbrp.mjs index 83a8c66..f3a0e47 100644 --- a/ringbrp.mjs +++ b/ringbrp.mjs @@ -6259,6 +6259,38 @@ async function migrateFittedGear() { return fixed; } +/** + * Dress this system's journals in the system's own paper. + * + * Twelve pages of generated rulebook, a player primer and a starter scenario were all + * rendering as Foundry's default parchment — the only part of the game that did not + * look like the game. Scoped by a flag rather than applied to every JournalSheet, so a + * module's journals in the same world are left exactly as they were. + */ +/** + * Dress this system's journals in the system's own paper. + * + * Twelve pages of generated rulebook, a ten-page player primer and a starter scenario + * were all rendering as Foundry's default parchment — the only part of the game that + * did not look like the game. Scoped by a flag rather than applied to every journal, so + * a module's entries in the same world are left exactly as they were. + * + * v14 note: the sheet is an ApplicationV2, so the hook is `renderJournalEntrySheet` and + * `element` is the root node itself rather than a jQuery wrapper. Reaching for `[0]` on + * it silently returns the first CHILD — which is how the first version of this appeared + * to work, added the class to a header button, and changed nothing. + */ +const rbBrandJournal = (doc, el) => { + const mine = doc?.flags?.ringbrp?.brand + || (typeof doc?.pack === "string" && doc.pack.startsWith("ringbrp.")) + || doc?.compendium?.metadata?.packageName === "ringbrp"; + const node = el instanceof HTMLElement ? el : (el?.[0] ?? null); + if (mine && node?.classList) node.classList.add("ringbrp-journal"); +}; +Hooks.on("renderJournalEntrySheet", (app, el) => rbBrandJournal(app?.document, el)); +Hooks.on("renderJournalEntryPageSheet", (app, el) => + rbBrandJournal(app?.document?.parent, el)); + Hooks.once("ready", async () => { console.log("RingBRP | ready"); if (!game.user.isGM) return; diff --git a/styles/ringbrp.css b/styles/ringbrp.css index 4b88fdd..9b3e015 100644 --- a/styles/ringbrp.css +++ b/styles/ringbrp.css @@ -36,6 +36,7 @@ .ringbrp-sheet, .ringbrp-chat, +.ringbrp-journal, .ringbrp-window { /* sampled from the 1984 Explorer Book cover */ --rb-void: #0c125b; @@ -423,6 +424,154 @@ .ringbrp-sheet .rb-equip:hover { color: var(--rb-white); } .ringbrp-sheet .rb-equip.on { color: var(--rb-yellow); } +/* ============================================================ + JOURNALS — the department's own paper + ============================================================ + Twelve pages of rulebook and a player primer were rendering as Foundry's default + parchment, which is the one place in the system that did not look like the system. + Scoped to .ringbrp-journal, applied by a hook to this system's entries only, so + other modules' journals are left alone. */ + +.ringbrp-journal .window-content, +.ringbrp-journal .journal-entry-content, +.ringbrp-journal .journal-entry-pages { background: var(--rb-deep); } + +/* The contents rail: this is how a player moves through ten pages. */ +.ringbrp-journal .journal-sidebar { + background: var(--rb-void); border-right: 1px solid var(--rb-line); +} +.ringbrp-journal .journal-sidebar .toc li.page { + font-family: var(--rb-display); font-size: 10px; letter-spacing: .05em; + text-transform: uppercase; color: var(--rb-muted); + border-bottom: 1px solid var(--rb-hairline); +} +.ringbrp-journal .journal-sidebar .toc li.page:hover { color: var(--rb-white); } +.ringbrp-journal .journal-sidebar .toc li.page.active, +.ringbrp-journal .journal-sidebar .toc li.page.readied { + color: var(--rb-void); background: var(--rb-yellow); +} +.ringbrp-journal .journal-header .title { + font-family: var(--rb-display); color: var(--rb-yellow); + background: transparent; border: none; +} + +/* A page. v14 puts the prose straight inside article.journal-entry-page — there is no + .journal-page-content wrapper, which is why the first version of this styled nothing. */ +.ringbrp-journal .journal-entry-page { + background: var(--rb-deep); + color: var(--rb-white); + font-family: var(--rb-body); + font-size: 14px; + line-height: 1.55; + padding: 4px 18px 28px; +} + +.ringbrp-journal .journal-entry-page h1 { + font-family: var(--rb-display); font-size: 19px; letter-spacing: .06em; + text-transform: uppercase; color: var(--rb-yellow); + border: none; border-bottom: 2px solid var(--rb-yellow); padding-bottom: 8px; + margin: 0 0 18px; +} +.ringbrp-journal .journal-entry-page h2 { + font-family: var(--rb-display); font-size: 13px; letter-spacing: .1em; + text-transform: uppercase; color: var(--rb-yellow); + border: none; border-bottom: 1px solid var(--rb-hairline); padding-bottom: 5px; + margin: 26px 0 12px; +} +.ringbrp-journal .journal-entry-page h3 { + font-family: var(--rb-display); font-size: 11px; letter-spacing: .09em; + text-transform: uppercase; color: var(--rb-white); border: none; margin: 20px 0 8px; +} +.ringbrp-journal .journal-entry-page p { margin: 0 0 12px; } +.ringbrp-journal .journal-entry-page strong { color: var(--rb-yellow); font-weight: 700; } +.ringbrp-journal .journal-entry-page em { color: var(--rb-muted); } +.ringbrp-journal .journal-entry-page a { color: var(--rb-yellow); } + +.ringbrp-journal .journal-entry-page ul, +.ringbrp-journal .journal-entry-page ol { margin: 0 0 14px; padding-left: 22px; } +.ringbrp-journal .journal-entry-page li { margin-bottom: 5px; } +.ringbrp-journal .journal-entry-page ul { list-style: none; padding-left: 16px; } +.ringbrp-journal .journal-entry-page ul > li:before { + content: "\25aa"; color: var(--rb-yellow); margin-left: -14px; margin-right: 8px; +} +.ringbrp-journal .journal-entry-page ol > li::marker { color: var(--rb-yellow); font-weight: 700; } + +.ringbrp-journal .journal-entry-page table { + width: 100%; border-collapse: collapse; margin: 0 0 16px; + background: var(--rb-void); border: 1px solid var(--rb-line); +} +.ringbrp-journal .journal-entry-page th { + font-family: var(--rb-display); font-size: 10px; letter-spacing: .08em; + text-transform: uppercase; text-align: left; color: var(--rb-void); + background: var(--rb-yellow); padding: 6px 9px; border: none; +} +.ringbrp-journal .journal-entry-page td { + padding: 6px 9px; border-top: 1px solid var(--rb-hairline); vertical-align: top; +} +.ringbrp-journal .journal-entry-page tbody tr:nth-child(even) { background: var(--rb-panel); } + +/* Read-aloud: the one thing a GM says in somebody else's voice. */ +.ringbrp-journal .rb-readaloud { + margin: 0 0 18px; padding: 12px 16px; + background: var(--rb-void); + border: none; border-left: 3px solid var(--rb-yellow); + color: var(--rb-white); font-size: 15px; line-height: 1.6; +} +.ringbrp-journal .rb-readaloud strong, +.ringbrp-journal .rb-readaloud em { color: var(--rb-yellow); } + +/* Maps and diagrams are typed, not drawn. */ +.ringbrp-journal .rb-map { + background: var(--rb-void); border: 1px solid var(--rb-line); + color: var(--rb-muted); font-family: var(--rb-mono); font-size: 11px; + line-height: 1.45; padding: 12px 14px; margin: 0 0 16px; + overflow-x: auto; white-space: pre; +} + +/* A departmental form: the stamped block a primer page opens with. */ +.ringbrp-journal .rb-form { + background: var(--rb-void); border: 1px solid var(--rb-line); + border-top: 3px solid var(--rb-yellow); + padding: 12px 14px; margin: 0 0 20px; + font-family: var(--rb-mono); font-size: 11px; line-height: 1.7; + color: var(--rb-muted); text-transform: uppercase; letter-spacing: .04em; +} +.ringbrp-journal .rb-form b { color: var(--rb-white); font-weight: 700; } +.ringbrp-journal .rb-stamp { + display: inline-block; border: 2px solid var(--rb-danger); color: var(--rb-danger); + font-family: var(--rb-display); font-size: 11px; letter-spacing: .14em; + text-transform: uppercase; padding: 4px 10px; transform: rotate(-2deg); + margin: 4px 0 14px; +} +/* The line a page lands on. */ +.ringbrp-journal .rb-closer { + font-family: var(--rb-display); font-size: 13px; letter-spacing: .05em; + color: var(--rb-yellow); text-align: center; + border-top: 1px solid var(--rb-hairline); padding-top: 16px; margin-top: 22px; +} +.ringbrp-journal .rb-two { columns: 260px 2; column-gap: 26px; } +.ringbrp-journal .rb-two > * { break-inside: avoid; } + +/* The cheat sheet: a card per rule, so it can be skimmed under pressure. */ +.ringbrp-journal .rb-cards { + display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); + gap: 12px; margin: 0 0 18px; +} +.ringbrp-journal .rb-card { + background: var(--rb-void); border: 1px solid var(--rb-line); + border-left: 3px solid var(--rb-yellow); padding: 10px 12px; +} +.ringbrp-journal .rb-card h4 { + font-family: var(--rb-display); font-size: 10px; letter-spacing: .09em; + text-transform: uppercase; color: var(--rb-yellow); margin: 0 0 6px; border: none; +} +.ringbrp-journal .rb-card p { margin: 0 0 6px; font-size: 13px; } +.ringbrp-journal .rb-card p:last-child { margin-bottom: 0; } +.ringbrp-journal .rb-big-number { + font-family: var(--rb-display); font-size: 22px; color: var(--rb-white); + line-height: 1.15; display: block; margin-bottom: 6px; +} + /* ============================================================ Shields — armour with a switch, so the switch has to be visible ============================================================ */ diff --git a/system.json b/system.json index b94b754..1278139 100644 --- a/system.json +++ b/system.json @@ -2,7 +2,7 @@ "id": "ringbrp", "title": "The Custodians", "description": "A Basic Roleplaying game of agents who cross the crossing to contain what should not be there — and who come back a little less from here each time.", - "version": "0.8.0", + "version": "0.9.0", "compatibility": { "minimum": 13, "verified": "14.364" @@ -113,6 +113,13 @@ "type": "Item", "system": "ringbrp" }, + { + "name": "primer", + "label": "The Custodians · Read this first (players)", + "path": "packs/primer", + "type": "JournalEntry", + "system": "ringbrp" + }, { "name": "rules", "label": "The Custodians · Rules", diff --git a/tools/build-packs.mjs b/tools/build-packs.mjs index 3c40e0e..8b757e4 100644 --- a/tools/build-packs.mjs +++ b/tools/build-packs.mjs @@ -622,6 +622,7 @@ await writePack("armour", ARMOURS.map(a => { // Handouts are for handing out. A GM who has to change ownership on seven pages // before the session starts will simply read them aloud instead. handouts.doc.ownership = { default: 2 }; + handouts.doc.flags = { ringbrp: { brand: true } }; for (const p of handouts.pages) p.ownership = { default: 2 }; const advId = idFor("adventure:black_platform"); @@ -656,10 +657,25 @@ await writePack("armour", ARMOURS.map(a => { + `${S.STARTER_PAGES.length} GM pages, ${S.STARTER_HANDOUTS.length} handouts`); } +// The player primer. Its own pack, OBSERVER by default, because it is the one thing +// in the system written to be handed to players before anybody has read a rule. +{ + const { PRIMER_PAGES } = await import("./primer-text.mjs"); + const j = journalDoc("The Custodians — Read this first", "primer", PRIMER_PAGES); + j.doc.ownership = { default: 2 }; + j.doc.flags = { ringbrp: { brand: true } }; + for (const pg of j.pages) pg.ownership = { default: 2 }; + const entries = [[`!journal!${j.id}`, j.doc]]; + for (const pg of j.pages) entries.push([`!journal.pages!${j.id}.${pg._id}`, pg]); + await writePack("primer", entries); + console.log(` primer ${PRIMER_PAGES.length} pages, player-visible`); +} + // the slice journal { const { SLICE_PAGES } = await import("./slice-text.mjs"); const j = journalDoc("The Ilfracombe Crossing", "slice", SLICE_PAGES); + j.doc.flags = { ringbrp: { brand: true } }; const entries = [[`!journal!${j.id}`, j.doc]]; for (const p of j.pages) entries.push([`!journal.pages!${j.id}.${p._id}`, p]); await writePack("slice", entries); @@ -693,6 +709,7 @@ await writePack("armour", ARMOURS.map(a => { { const { RULES_PAGES } = await import("./rules-text.mjs"); const j = journalDoc("The Custodians — Rules", "rules", RULES_PAGES); + j.doc.flags = { ringbrp: { brand: true } }; const entries = [[`!journal!${j.id}`, j.doc]]; for (const p of j.pages) entries.push([`!journal.pages!${j.id}.${p._id}`, p]); await writePack("rules", entries); diff --git a/tools/primer-text.mjs b/tools/primer-text.mjs new file mode 100644 index 0000000..4b3c9dd --- /dev/null +++ b/tools/primer-text.mjs @@ -0,0 +1,502 @@ +/** + * THE PLAYER PRIMER — what a new player reads before session one. + * + * Written to be handed out, not studied. Eight pages of setting and one cheat sheet, + * and the cheat sheet's numbers are computed from rules.mjs at build time so the card + * a player holds cannot say one thing while the engine does another. That failure has + * happened five times in this project; a hand-typed cheat sheet would have been the + * sixth, and it would have been the one the players were looking at. + * + * On the voice: the source draft called the organisation "the Bureau". Everything else + * in the game — twelve rules pages, the starter, every localisation string — calls it + * "the department" or "the agency", so that is what it is called here. One name. + */ +// TRADE_BANDS and INDUCTION are register data, not rules — they live in postings.mjs. +import { TRADE_BANDS, INDUCTION } from "../postings.mjs"; +import { + hitPointsFor, majorWoundFor, damageModifierFor, defencePenaltyFor, + COHERENCE_BANDS, RANGE_LADDER, CIRCUMSTANCE +} from "../rules.mjs"; +import { readFile } from "node:fs/promises"; + +// Labels come from the language file, the same way the rulebook generator reads them, +// so the primer prints what the sheet prints rather than a prettified lang key. +const LANG = JSON.parse(await readFile(new URL("../lang/en.json", import.meta.url), "utf8")); +const L = key => LANG[key] ?? key; + +const P = s => `
${s}
`; +const H = (n, s) => `| ${h} | `).join("")}
|---|
| ${c} | `).join("")}
${s}`; +const FORM = s => `
${s}
`; +const CARDS = xs => `