@bongos/core 1.24.93 → 1.24.95
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/.bongos-core.json +123 -33
- package/docs/adr/0404-a-party-is-a-room-and-rooms-register-as-kinds.md +118 -0
- package/docs/adr/0405-each-character-has-one-colour-and-the-visor-wears-it.md +31 -0
- package/docs/adr/README.md +2 -0
- package/docs/copy-inventory.md +7 -7
- package/docs/copy-registry.json +7 -7
- package/docs/design/characters/v2/artisan-visor.png +0 -0
- package/docs/design/characters/v2/artisan.png +0 -0
- package/docs/design/characters/v2/artist-visor.png +0 -0
- package/docs/design/characters/v2/artist.png +0 -0
- package/docs/design/characters/v2/draw-characters.js +465 -0
- package/docs/design/characters/v2/patron-visor.png +0 -0
- package/docs/design/characters/v2/patron.png +0 -0
- package/docs/design/characters/v2/sheet.html +114 -0
- package/docs/module-api-changelog.md +4 -0
- package/docs/modules-contract.md +2 -0
- package/docs/page-readings.json +35 -35
- package/modules/hall-ui/public/characters/artisan-face.png +0 -0
- package/modules/hall-ui/public/characters/artisan-visor.png +0 -0
- package/modules/hall-ui/public/characters/artisan.png +0 -0
- package/modules/hall-ui/public/characters/artist-face.png +0 -0
- package/modules/hall-ui/public/characters/artist-visor.png +0 -0
- package/modules/hall-ui/public/characters/artist.png +0 -0
- package/modules/hall-ui/public/characters/patron-face.png +0 -0
- package/modules/hall-ui/public/characters/patron-visor.png +0 -0
- package/modules/hall-ui/public/characters/patron.png +0 -0
- package/modules/hall-ui/public/craft-mode.js +15 -4
- package/modules/hall-ui/public/home-city.js +14 -3
- package/modules/hall-ui/public/home-gallery.css +6 -0
- package/modules/hall-ui/public/home-gallery.js +30 -0
- package/modules/hall-ui/public/style.css +18 -5
- package/modules/hall-ui/public/visor.css +20 -5
- package/modules/hall-ui/public/visor.js +6 -3
- package/modules/hall-ui/records/characters.md +19 -0
- package/modules/hall-ui/records/visor.md +10 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +20 -0
- package/src/module-api.js +1 -1
- package/src/module-seams.js +3 -0
- package/tests/character_creation.mjs +44 -7
- package/tests/hall_visor.mjs +28 -2
- package/tests/home_gallery_widget.mjs +43 -0
- package/tests/room_kinds_seam.mjs +68 -0
package/docs/page-readings.json
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"surface": "builders",
|
|
13
13
|
"title": "Studio",
|
|
14
14
|
"states_read": ["pick","describe","make","waiting","result","result-own","failed","balance","balance-all","out"],
|
|
15
|
-
"files_hash": "
|
|
15
|
+
"files_hash": "bfd352bc483d41c2",
|
|
16
16
|
"reading_hash": "d9e0e85bcee4aff4",
|
|
17
17
|
"counts": {"lines":106,"placed":41,"shared":7,"unplaced":58},
|
|
18
18
|
"omitted": {"data":17},
|
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
"surface": "builders",
|
|
132
132
|
"title": "Repo Atlas",
|
|
133
133
|
"states_read": ["map","truth","detail","index","out"],
|
|
134
|
-
"files_hash": "
|
|
134
|
+
"files_hash": "133220425bccce34",
|
|
135
135
|
"reading_hash": "6934dead335b2507",
|
|
136
136
|
"counts": {"lines":25,"placed":14,"shared":7,"unplaced":4},
|
|
137
137
|
"omitted": {"data":5},
|
|
@@ -169,7 +169,7 @@
|
|
|
169
169
|
"surface": "builders",
|
|
170
170
|
"title": "Blockers",
|
|
171
171
|
"states_read": ["default"],
|
|
172
|
-
"files_hash": "
|
|
172
|
+
"files_hash": "a819c6030cf15a6e",
|
|
173
173
|
"reading_hash": "60d73d854ced958a",
|
|
174
174
|
"counts": {"lines":36,"placed":17,"shared":7,"unplaced":12},
|
|
175
175
|
"omitted": {"data":51},
|
|
@@ -218,7 +218,7 @@
|
|
|
218
218
|
"surface": "builders",
|
|
219
219
|
"title": "Board Room",
|
|
220
220
|
"states_read": ["room","out","sitting-meta","objection-form"],
|
|
221
|
-
"files_hash": "
|
|
221
|
+
"files_hash": "649b8241ac4ad473",
|
|
222
222
|
"reading_hash": "0260b797b8dc1526",
|
|
223
223
|
"counts": {"lines":52,"placed":21,"shared":7,"unplaced":24},
|
|
224
224
|
"omitted": {"data":17},
|
|
@@ -283,7 +283,7 @@
|
|
|
283
283
|
"surface": "builders",
|
|
284
284
|
"title": "The city",
|
|
285
285
|
"states_read": ["city","fullscreen","focus","pins","living","card","card-ask"],
|
|
286
|
-
"files_hash": "
|
|
286
|
+
"files_hash": "804ce56d156d7046",
|
|
287
287
|
"reading_hash": "277096d903879a57",
|
|
288
288
|
"counts": {"lines":26,"placed":9,"shared":6,"unplaced":11},
|
|
289
289
|
"omitted": {"data":7},
|
|
@@ -322,7 +322,7 @@
|
|
|
322
322
|
"surface": "builders",
|
|
323
323
|
"title": "Collab",
|
|
324
324
|
"states_read": ["board","out"],
|
|
325
|
-
"files_hash": "
|
|
325
|
+
"files_hash": "6e58d1336b59ed6d",
|
|
326
326
|
"reading_hash": "e6452bf92231656f",
|
|
327
327
|
"counts": {"lines":82,"placed":36,"shared":6,"unplaced":40},
|
|
328
328
|
"omitted": {"data":23},
|
|
@@ -417,7 +417,7 @@
|
|
|
417
417
|
"surface": "builders",
|
|
418
418
|
"title": "Commands",
|
|
419
419
|
"states_read": ["in","out"],
|
|
420
|
-
"files_hash": "
|
|
420
|
+
"files_hash": "6c7abde80e1c7a74",
|
|
421
421
|
"reading_hash": "ecc452689a8ee9d7",
|
|
422
422
|
"counts": {"lines":71,"placed":49,"shared":7,"unplaced":15},
|
|
423
423
|
"omitted": {"data":177},
|
|
@@ -501,7 +501,7 @@
|
|
|
501
501
|
"surface": "builders",
|
|
502
502
|
"title": "Copy desk",
|
|
503
503
|
"states_read": ["queue","out","search","composer","closer","proposer"],
|
|
504
|
-
"files_hash": "
|
|
504
|
+
"files_hash": "1f6a0864849d0263",
|
|
505
505
|
"reading_hash": "3819ef6fa8f6fb7c",
|
|
506
506
|
"counts": {"lines":72,"placed":36,"shared":7,"unplaced":29},
|
|
507
507
|
"omitted": {"data":94},
|
|
@@ -586,7 +586,7 @@
|
|
|
586
586
|
"surface": "builders",
|
|
587
587
|
"title": "Deploy",
|
|
588
588
|
"states_read": ["work","out"],
|
|
589
|
-
"files_hash": "
|
|
589
|
+
"files_hash": "b534665c0eb1a176",
|
|
590
590
|
"reading_hash": "3770e8b2fa56bee1",
|
|
591
591
|
"counts": {"lines":14,"placed":5,"shared":7,"unplaced":2},
|
|
592
592
|
"omitted": {"data":5},
|
|
@@ -613,7 +613,7 @@
|
|
|
613
613
|
"surface": "builders",
|
|
614
614
|
"title": "The sky",
|
|
615
615
|
"states_read": ["tour","sky","wells","ledger","full","full-back","out"],
|
|
616
|
-
"files_hash": "
|
|
616
|
+
"files_hash": "a5f2d9cada6d1773",
|
|
617
617
|
"reading_hash": "4a879397a84631e3",
|
|
618
618
|
"counts": {"lines":50,"placed":25,"shared":6,"unplaced":19},
|
|
619
619
|
"omitted": {"data":10},
|
|
@@ -676,7 +676,7 @@
|
|
|
676
676
|
"surface": "builders",
|
|
677
677
|
"title": "Goals",
|
|
678
678
|
"states_read": ["list","filters","cards","detail","dependencies","out","uat","uat-panel","author"],
|
|
679
|
-
"files_hash": "
|
|
679
|
+
"files_hash": "83d51fe0a0cbdc81",
|
|
680
680
|
"reading_hash": "13a5d07b3804b627",
|
|
681
681
|
"counts": {"lines":187,"placed":61,"shared":7,"unplaced":119},
|
|
682
682
|
"omitted": {"data":315},
|
|
@@ -876,7 +876,7 @@
|
|
|
876
876
|
"surface": "builders",
|
|
877
877
|
"title": "Government",
|
|
878
878
|
"states_read": ["constitution","out","permissions","board","constitution-tab"],
|
|
879
|
-
"files_hash": "
|
|
879
|
+
"files_hash": "67e03165f6801e25",
|
|
880
880
|
"reading_hash": "37c6878d60447fd6",
|
|
881
881
|
"counts": {"lines":65,"placed":27,"shared":7,"unplaced":31},
|
|
882
882
|
"omitted": {"data":276},
|
|
@@ -954,8 +954,8 @@
|
|
|
954
954
|
"surface": "builders",
|
|
955
955
|
"title": "Builders' Hall",
|
|
956
956
|
"states_read": ["home","out","founding","genesis","decide","demo"],
|
|
957
|
-
"files_hash": "
|
|
958
|
-
"reading_hash": "
|
|
957
|
+
"files_hash": "057978d931dfd529",
|
|
958
|
+
"reading_hash": "c46b0ff89002a2d9",
|
|
959
959
|
"counts": {"lines":32,"placed":12,"shared":8,"unplaced":12},
|
|
960
960
|
"omitted": {"data":5},
|
|
961
961
|
"notes": ["founding: an action failed (page.focus: Timeout 6000ms exceeded.); read as it stood"],
|
|
@@ -977,7 +977,7 @@
|
|
|
977
977
|
{"key":"L0015","section":"Needs your attention13","text":"Ideas awaiting triage","placement":"placed","file":"modules/hall-ui/public/builders.js","line":320,"string_id":"e181637c5a5e"},
|
|
978
978
|
{"key":"L0016","section":"Needs your attention13","text":"Requires project {…} fix","placement":"unplaced"},
|
|
979
979
|
{"key":"L0017","section":"footer","text":"Sign out","placement":"shared","file":"modules/hall-ui/public/shell.js","line":514,"string_id":"1883ad7f07fc"},
|
|
980
|
-
{"key":"L0018","section":"Needs your attention13","text":"core 1.24.
|
|
980
|
+
{"key":"L0018","section":"Needs your attention13","text":"core 1.24.93","placement":"unplaced"},
|
|
981
981
|
{"key":"L0019","section":"Needs your attention13","text":"Skip","placement":"unplaced"},
|
|
982
982
|
{"key":"L0020","section":"Needs your attention13","text":"Built on","placement":"placed","file":"modules/hall-ui/public/welcome-boot.js","line":183,"string_id":"fef59346ffee"},
|
|
983
983
|
{"key":"L0021","section":"Needs your attention13","text":"cloudbongos.com","placement":"unplaced"},
|
|
@@ -999,7 +999,7 @@
|
|
|
999
999
|
"surface": "builders",
|
|
1000
1000
|
"title": "Idea",
|
|
1001
1001
|
"states_read": ["record","missing"],
|
|
1002
|
-
"files_hash": "
|
|
1002
|
+
"files_hash": "b19a972d3190b27c",
|
|
1003
1003
|
"reading_hash": "f7d644748c87e426",
|
|
1004
1004
|
"counts": {"lines":52,"placed":25,"shared":8,"unplaced":19},
|
|
1005
1005
|
"omitted": {"data":25},
|
|
@@ -1064,7 +1064,7 @@
|
|
|
1064
1064
|
"surface": "builders",
|
|
1065
1065
|
"title": "Ideas",
|
|
1066
1066
|
"states_read": ["compose","full","develop"],
|
|
1067
|
-
"files_hash": "
|
|
1067
|
+
"files_hash": "65f50755fa5d2c77",
|
|
1068
1068
|
"reading_hash": "a62c05dcef3bf87f",
|
|
1069
1069
|
"counts": {"lines":68,"placed":34,"shared":7,"unplaced":27},
|
|
1070
1070
|
"omitted": {"data":118},
|
|
@@ -1145,7 +1145,7 @@
|
|
|
1145
1145
|
"surface": "builders",
|
|
1146
1146
|
"title": "Market Watch",
|
|
1147
1147
|
"states_read": ["desk","settings","out"],
|
|
1148
|
-
"files_hash": "
|
|
1148
|
+
"files_hash": "2685309696818881",
|
|
1149
1149
|
"reading_hash": "30512dda207b5ea6",
|
|
1150
1150
|
"counts": {"lines":23,"placed":11,"shared":7,"unplaced":5},
|
|
1151
1151
|
"omitted": {"data":5},
|
|
@@ -1181,7 +1181,7 @@
|
|
|
1181
1181
|
"surface": "builders",
|
|
1182
1182
|
"title": "Market Watch",
|
|
1183
1183
|
"states_read": ["dossier","out","propose","correct","filtered"],
|
|
1184
|
-
"files_hash": "
|
|
1184
|
+
"files_hash": "4dd2ab01e84c217f",
|
|
1185
1185
|
"reading_hash": "129bff28c4e4ed6d",
|
|
1186
1186
|
"counts": {"lines":24,"placed":12,"shared":7,"unplaced":5},
|
|
1187
1187
|
"omitted": {"data":5},
|
|
@@ -1218,7 +1218,7 @@
|
|
|
1218
1218
|
"surface": "builders",
|
|
1219
1219
|
"title": "Market Watch rules",
|
|
1220
1220
|
"states_read": ["in","scoring","names","propose","out"],
|
|
1221
|
-
"files_hash": "
|
|
1221
|
+
"files_hash": "526c2149de84f633",
|
|
1222
1222
|
"reading_hash": "ca0c62e8dce51c8b",
|
|
1223
1223
|
"counts": {"lines":36,"placed":12,"shared":7,"unplaced":17},
|
|
1224
1224
|
"omitted": {"data":20},
|
|
@@ -1267,7 +1267,7 @@
|
|
|
1267
1267
|
"surface": "builders",
|
|
1268
1268
|
"title": "Modules",
|
|
1269
1269
|
"states_read": ["browse","search-empty","lens","details","out"],
|
|
1270
|
-
"files_hash": "
|
|
1270
|
+
"files_hash": "574e1738477d342c",
|
|
1271
1271
|
"reading_hash": "6a12e9306bba5622",
|
|
1272
1272
|
"counts": {"lines":59,"placed":29,"shared":7,"unplaced":23},
|
|
1273
1273
|
"omitted": {"data":107},
|
|
@@ -1339,7 +1339,7 @@
|
|
|
1339
1339
|
"surface": "builders",
|
|
1340
1340
|
"title": "Money",
|
|
1341
1341
|
"states_read": ["money","hosting","out"],
|
|
1342
|
-
"files_hash": "
|
|
1342
|
+
"files_hash": "816343bf158f836b",
|
|
1343
1343
|
"reading_hash": "e355d5466b123e07",
|
|
1344
1344
|
"counts": {"lines":83,"placed":28,"shared":7,"unplaced":48},
|
|
1345
1345
|
"omitted": {"data":27},
|
|
@@ -1435,7 +1435,7 @@
|
|
|
1435
1435
|
"surface": "builders",
|
|
1436
1436
|
"title": "My agents",
|
|
1437
1437
|
"states_read": ["desk","factory","saved","what-it-knows","speciality-walk","speciality-forms","nobody"],
|
|
1438
|
-
"files_hash": "
|
|
1438
|
+
"files_hash": "3e69046bdd44b756",
|
|
1439
1439
|
"reading_hash": "5347e0496b38727d",
|
|
1440
1440
|
"counts": {"lines":100,"placed":33,"shared":7,"unplaced":60},
|
|
1441
1441
|
"omitted": {"data":38},
|
|
@@ -1548,7 +1548,7 @@
|
|
|
1548
1548
|
"surface": "builders",
|
|
1549
1549
|
"title": "Primer",
|
|
1550
1550
|
"states_read": ["in","toc-open","jump","out"],
|
|
1551
|
-
"files_hash": "
|
|
1551
|
+
"files_hash": "da0299600036bb6f",
|
|
1552
1552
|
"reading_hash": "85790bd421e5c387",
|
|
1553
1553
|
"counts": {"lines":487,"placed":57,"shared":7,"unplaced":423},
|
|
1554
1554
|
"omitted": {"data":18},
|
|
@@ -2048,7 +2048,7 @@
|
|
|
2048
2048
|
"surface": "builders",
|
|
2049
2049
|
"title": "Profile",
|
|
2050
2050
|
"states_read": ["own","works","activity","yours","activity-artist","activity-artist-ideas","other","artist","artist-ideas","out"],
|
|
2051
|
-
"files_hash": "
|
|
2051
|
+
"files_hash": "88fc36c8238827bf",
|
|
2052
2052
|
"reading_hash": "3ff8d703d17e8c2a",
|
|
2053
2053
|
"counts": {"lines":232,"placed":84,"shared":7,"unplaced":141},
|
|
2054
2054
|
"omitted": {"data":263},
|
|
@@ -2293,7 +2293,7 @@
|
|
|
2293
2293
|
"surface": "builders",
|
|
2294
2294
|
"title": "Project settings",
|
|
2295
2295
|
"states_read": ["default"],
|
|
2296
|
-
"files_hash": "
|
|
2296
|
+
"files_hash": "dec5d7d8359c913d",
|
|
2297
2297
|
"reading_hash": "283df27d0d5bfc1b",
|
|
2298
2298
|
"counts": {"lines":43,"placed":25,"shared":7,"unplaced":11},
|
|
2299
2299
|
"omitted": {"data":33},
|
|
@@ -2349,7 +2349,7 @@
|
|
|
2349
2349
|
"surface": "builders",
|
|
2350
2350
|
"title": "Builders",
|
|
2351
2351
|
"states_read": ["roster","artists","search","out"],
|
|
2352
|
-
"files_hash": "
|
|
2352
|
+
"files_hash": "eada2a8ff8a184ab",
|
|
2353
2353
|
"reading_hash": "665ac2e36339f5d3",
|
|
2354
2354
|
"counts": {"lines":56,"placed":17,"shared":7,"unplaced":32},
|
|
2355
2355
|
"omitted": {"data":137},
|
|
@@ -2418,7 +2418,7 @@
|
|
|
2418
2418
|
"surface": "builders",
|
|
2419
2419
|
"title": "Options",
|
|
2420
2420
|
"states_read": ["account","access","preferences","install-reports","sound","update"],
|
|
2421
|
-
"files_hash": "
|
|
2421
|
+
"files_hash": "9ee8d40cdee36f53",
|
|
2422
2422
|
"reading_hash": "898a13fda24c3c90",
|
|
2423
2423
|
"counts": {"lines":162,"placed":104,"shared":7,"unplaced":51},
|
|
2424
2424
|
"omitted": {"data":23},
|
|
@@ -2593,7 +2593,7 @@
|
|
|
2593
2593
|
"surface": "builders",
|
|
2594
2594
|
"title": "The street",
|
|
2595
2595
|
"states_read": ["street","fullscreen","card","focus","here","inside-rules","inside-disputes","inside-people","inside-planning","inside-automation","inside-review","inside-release","inside-treasury","floor","amend","district","desk","desk-facts","desk-quiet","desk-people-builders","desk-people-tier","desk-disputes","desk-automation-goals","desk-release-core","desk-rules","desk-rules-category","desk-planning-priorities","desk-planning-ideas","desk-planning-blockers","pins","pins-pager","living","deck","deck-treasury","sitting","object","voted","admission","settled","blocker","blocker-more","report","report-more","core","core-more","recheck","recheck-more","idea","idea-more","queue","queue-more","automation","automation-more"],
|
|
2596
|
-
"files_hash": "
|
|
2596
|
+
"files_hash": "b034bee92146665b",
|
|
2597
2597
|
"reading_hash": "e788e6bf4be8d68c",
|
|
2598
2598
|
"counts": {"lines":325,"placed":54,"shared":6,"unplaced":265},
|
|
2599
2599
|
"omitted": {"data":240},
|
|
@@ -2931,7 +2931,7 @@
|
|
|
2931
2931
|
"surface": "builders",
|
|
2932
2932
|
"title": "Studio",
|
|
2933
2933
|
"states_read": ["home","out","flow","flow-pick","status","words-offer","words-edit","reviews","full","full-back","approvals","approvals-before","approvals-phone","approvals-note","approved","sent-back","approvals-page"],
|
|
2934
|
-
"files_hash": "
|
|
2934
|
+
"files_hash": "c01cf7220bebfb79",
|
|
2935
2935
|
"reading_hash": "c4e3b4188c1db755",
|
|
2936
2936
|
"counts": {"lines":51,"placed":29,"shared":7,"unplaced":15},
|
|
2937
2937
|
"omitted": {"data":23},
|
|
@@ -2995,7 +2995,7 @@
|
|
|
2995
2995
|
"surface": "builders",
|
|
2996
2996
|
"title": "Task",
|
|
2997
2997
|
"states_read": ["record","from-goal","missing"],
|
|
2998
|
-
"files_hash": "
|
|
2998
|
+
"files_hash": "91a9c833cdebb28b",
|
|
2999
2999
|
"reading_hash": "8dd803b6934e6388",
|
|
3000
3000
|
"counts": {"lines":151,"placed":46,"shared":9,"unplaced":96},
|
|
3001
3001
|
"omitted": {"data":111},
|
|
@@ -3159,7 +3159,7 @@
|
|
|
3159
3159
|
"surface": "builders",
|
|
3160
3160
|
"title": "Your thinking",
|
|
3161
3161
|
"states_read": ["tour","sky","list","simple","full-idea","full","full-list","full-back","out"],
|
|
3162
|
-
"files_hash": "
|
|
3162
|
+
"files_hash": "fa151338327f0a86",
|
|
3163
3163
|
"reading_hash": "b73f848b46b0f9b8",
|
|
3164
3164
|
"counts": {"lines":50,"placed":25,"shared":6,"unplaced":19},
|
|
3165
3165
|
"omitted": {"data":10},
|
|
@@ -3222,7 +3222,7 @@
|
|
|
3222
3222
|
"surface": "builders",
|
|
3223
3223
|
"title": "Tweak a page",
|
|
3224
3224
|
"states_read": ["doc","typed","chrome","submitted","picking","out"],
|
|
3225
|
-
"files_hash": "
|
|
3225
|
+
"files_hash": "f52e3d547a72e46c",
|
|
3226
3226
|
"reading_hash": "f521f8d9a7147557",
|
|
3227
3227
|
"counts": {"lines":26,"placed":18,"shared":2,"unplaced":6},
|
|
3228
3228
|
"omitted": {"data":19},
|
|
@@ -3261,7 +3261,7 @@
|
|
|
3261
3261
|
"surface": "builders",
|
|
3262
3262
|
"title": "Watch",
|
|
3263
3263
|
"states_read": ["board","out","operations","security","sessions","autobongos"],
|
|
3264
|
-
"files_hash": "
|
|
3264
|
+
"files_hash": "8c900aaef19935e9",
|
|
3265
3265
|
"reading_hash": "1961a0c06b9d8477",
|
|
3266
3266
|
"counts": {"lines":72,"placed":33,"shared":7,"unplaced":32},
|
|
3267
3267
|
"omitted": {"data":52},
|
|
@@ -3346,7 +3346,7 @@
|
|
|
3346
3346
|
"surface": "builders",
|
|
3347
3347
|
"title": "Tasks",
|
|
3348
3348
|
"states_read": ["ready","in-progress","backlog","completed","filters-open","out","founding"],
|
|
3349
|
-
"files_hash": "
|
|
3349
|
+
"files_hash": "932f03e5ce99e576",
|
|
3350
3350
|
"reading_hash": "e9b412d1ec59ceee",
|
|
3351
3351
|
"counts": {"lines":122,"placed":49,"shared":7,"unplaced":66},
|
|
3352
3352
|
"omitted": {"data":323},
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -830,8 +830,12 @@
|
|
|
830
830
|
// clears the pick and signs out, and the next sign-in finds none and asks again.
|
|
831
831
|
// Identity and view only — rank still gates every verb on the server (ADR 0016).
|
|
832
832
|
//
|
|
833
|
-
// The sprites are the
|
|
834
|
-
//
|
|
833
|
+
// The sprites are the second look (task 1005218): 64x64 pixel art, two animals in one
|
|
834
|
+
// body (Artisan a ram on a lizard, Artist an ibis on an octopus, Patron a falcon on a
|
|
835
|
+
// lion), each with one colour of its own (style.css --char-*). Three files per character
|
|
836
|
+
// under characters/: <id>.png the whole figure, <id>-face.png the head (the chip),
|
|
837
|
+
// <id>-visor.png the head wearing the visor (the visor's corner). All are DRAWN by
|
|
838
|
+
// docs/design/characters/v2/draw-characters.js --hall, never edited by hand.
|
|
835
839
|
var account; // undefined: not told; null: none picked; else the character
|
|
836
840
|
var creating = false; // the preselected door while character creation is open
|
|
837
841
|
var CHAR_KEY = 'hall-character'; // localStorage: the last held character, so the first paint is right
|
|
@@ -841,9 +845,14 @@
|
|
|
841
845
|
patron: 'Watch the project, propose, and with a seat decide.',
|
|
842
846
|
};
|
|
843
847
|
// Only ever one of the three names reaches the URL (valid() is the allowlist).
|
|
844
|
-
function
|
|
848
|
+
function pictureSrc(id, part) { return '/builders/characters/' + (valid(id) || 'artisan') + (part ? '-' + part : '') + '.png' + (SCRIPT_V ? '?v=' + SCRIPT_V : ''); }
|
|
849
|
+
function spriteSrc(id) { return pictureSrc(id, ''); }
|
|
850
|
+
// The head alone, and the head wearing the visor (what the visor shows of you).
|
|
851
|
+
function faceSrc(id) { return pictureSrc(id, 'face'); }
|
|
852
|
+
function portraitSrc(id) { return pictureSrc(id, 'visor'); }
|
|
845
853
|
function spriteHtml(id, cls) {
|
|
846
|
-
|
|
854
|
+
var face = cls === 'craft-sprite--chip';
|
|
855
|
+
return '<img class="craft-sprite ' + cls + '" src="' + (face ? faceSrc(id) : spriteSrc(id)) + '" alt="" width="' + (face ? 32 : 64) + '" height="' + (face ? 32 : 64) + '" decoding="async">';
|
|
847
856
|
}
|
|
848
857
|
function heldCharacter() {
|
|
849
858
|
if (typeof account === 'string') return account;
|
|
@@ -1061,6 +1070,8 @@
|
|
|
1061
1070
|
character: function () { return account; },
|
|
1062
1071
|
changeCharacter: changeCharacter,
|
|
1063
1072
|
spriteSrc: spriteSrc,
|
|
1073
|
+
faceSrc: faceSrc,
|
|
1074
|
+
portraitSrc: portraitSrc,
|
|
1064
1075
|
// task 1005148: the visor's two reads — the /me the gate saw, and a tool by id.
|
|
1065
1076
|
me: function () { return lastMe; },
|
|
1066
1077
|
// A tool opens only for the character whose tool it is (task 1005207): the
|
|
@@ -347,17 +347,28 @@
|
|
|
347
347
|
wireTip();
|
|
348
348
|
wireDoors();
|
|
349
349
|
if (window.OTBHomeGallery) gallery = window.OTBHomeGallery.attach(host);
|
|
350
|
+
if (gallery && gallery.onChange) gallery.onChange(registerScene);
|
|
350
351
|
if (window.OTBHomeIdeaBox) ideaBox = window.OTBHomeIdeaBox.attach(host);
|
|
351
352
|
document.addEventListener('otb:craft', craftHome);
|
|
352
353
|
craftHome();
|
|
353
354
|
new MutationObserver(() => { if (model) drawScene(); }).observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] });
|
|
354
355
|
document.addEventListener('otb:craft', () => { if (model) { drawScene(); drawLadder(); } });
|
|
355
356
|
window.addEventListener('resize', () => { if (model) drawLadder(); });
|
|
356
|
-
|
|
357
|
-
window.__visorScene = { name: 'home', place: 'Home' };
|
|
358
|
-
if (window.OTBVisor) window.OTBVisor.scene(window.__visorScene);
|
|
357
|
+
registerScene();
|
|
359
358
|
load();
|
|
360
359
|
}
|
|
360
|
+
// task 1005148: Home's city as the visor's scene; R13 adds its camera's actions here.
|
|
361
|
+
// task 1005211 (ADR 0403): in Artistry Home is the gallery, and its controls are the visor's:
|
|
362
|
+
// the gallery's own rows (home-gallery.js visorActions), registered again when they change.
|
|
363
|
+
let sceneSig = null;
|
|
364
|
+
function registerScene() {
|
|
365
|
+
const actions = gallery && gallery.visorActions ? gallery.visorActions() : [];
|
|
366
|
+
const sig = actions.map((a) => a.label + '|' + (a.key || '')).join('\n');
|
|
367
|
+
if (sig === sceneSig && window.__visorScene) return;
|
|
368
|
+
sceneSig = sig;
|
|
369
|
+
window.__visorScene = { name: 'home', place: 'Home', actions };
|
|
370
|
+
if (window.OTBVisor) window.OTBVisor.scene(window.__visorScene);
|
|
371
|
+
}
|
|
361
372
|
|
|
362
373
|
window.OTB.contributeHallWidget({
|
|
363
374
|
id: 'home-city', label: 'The project', order: 15, core: true, mount,
|
|
@@ -127,3 +127,9 @@
|
|
|
127
127
|
.hg-count { left: 50%; }
|
|
128
128
|
.hg-salon { left: 20px; right: 20px; top: 196px; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 22px 16px; }
|
|
129
129
|
}
|
|
130
|
+
|
|
131
|
+
/* task 1005211 (ADR 0403): in game mode the visor is the control and the gallery is the view.
|
|
132
|
+
Its order tabs, its ways (the full gallery, your studio), the arrows and the full-screen
|
|
133
|
+
button are rows on the visor (home-gallery.js visorActions); looking along the wall, a work's
|
|
134
|
+
label, its heart and a piece in the full gallery stay in the scene. Classic mode is as it was. */
|
|
135
|
+
html.visor-on .hg-sort, html.visor-on .hg-ways, html.visor-on .hg-edge, html.visor-on .hg-fsbtn { display: none; }
|
|
@@ -122,6 +122,29 @@
|
|
|
122
122
|
var room = root.querySelector('.hg-room'), track = root.querySelector('.hg-track'), salon = root.querySelector('.hg-salon');
|
|
123
123
|
var prev = root.querySelector('.hg-prev'), next = root.querySelector('.hg-next'), count = root.querySelector('.hg-count');
|
|
124
124
|
var wayAll = root.querySelector('.hg-way-all'), empty = root.querySelector('.hg-empty');
|
|
125
|
+
var fsbtn = root.querySelector('.hg-fsbtn'), studio = root.querySelector('a.hg-way');
|
|
126
|
+
// task 1005211 (ADR 0403): in game mode the gallery's tabs, ways, arrows and full-screen
|
|
127
|
+
// button are the visor's (home-gallery.css hides them under html.visor-on). These are
|
|
128
|
+
// their rows, each pressing the gallery's own control, in the control's own words; Home
|
|
129
|
+
// (home-city.js) registers them as the scene's actions and asks again when they change.
|
|
130
|
+
var changed = function () {};
|
|
131
|
+
function visorActions() {
|
|
132
|
+
if (root.hidden) return [];
|
|
133
|
+
var all = room.classList.contains('is-all');
|
|
134
|
+
var out = [{ label: wayAll.firstChild.textContent.trim(), key: 'g', bind: true, lead: true, run: function () { wayAll.click(); room.focus(); } }];
|
|
135
|
+
root.querySelectorAll('.hg-sort button').forEach(function (b) {
|
|
136
|
+
out.push({ label: b.textContent + (b.getAttribute('aria-pressed') === 'true' ? ' · on' : ' · off'), run: function () { b.click(); } });
|
|
137
|
+
});
|
|
138
|
+
// the wall's own keys answer once the room has the keyboard, so a row hands it over
|
|
139
|
+
if (!all && list.length) {
|
|
140
|
+
out.push({ label: prev.getAttribute('aria-label'), key: '←', run: function () { prev.click(); room.focus(); } });
|
|
141
|
+
out.push({ label: next.getAttribute('aria-label'), key: '→', run: function () { next.click(); room.focus(); } });
|
|
142
|
+
out.push({ label: 'Full screen', key: 'F', run: function () { fsbtn.click(); room.focus(); } });
|
|
143
|
+
}
|
|
144
|
+
var href = studio.getAttribute('href');
|
|
145
|
+
out.push({ label: studio.firstChild.textContent.trim(), run: function () { window.location.assign(href); } });
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
125
148
|
room.setAttribute('aria-label', ROOM_LABEL);
|
|
126
149
|
|
|
127
150
|
function hang(w, i) {
|
|
@@ -239,6 +262,7 @@
|
|
|
239
262
|
wayAll.firstChild.textContent = on ? 'Back to the bench ' : 'The full gallery ';
|
|
240
263
|
room.setAttribute('aria-label', on ? ALL_LABEL : ROOM_LABEL);
|
|
241
264
|
if (on) renderSalon();
|
|
265
|
+
changed();
|
|
242
266
|
}
|
|
243
267
|
|
|
244
268
|
// ---- full screen: the art alone, with its signature and heart ----
|
|
@@ -264,6 +288,7 @@
|
|
|
264
288
|
if (order === b.dataset.order) return;
|
|
265
289
|
order = b.dataset.order;
|
|
266
290
|
root.querySelectorAll('.hg-sort button').forEach(function (x) { x.setAttribute('aria-pressed', String(x === b)); });
|
|
291
|
+
changed();
|
|
267
292
|
load();
|
|
268
293
|
});
|
|
269
294
|
});
|
|
@@ -327,6 +352,7 @@
|
|
|
327
352
|
if (mine !== asking) return;
|
|
328
353
|
list = res && res.ok && res.data && Array.isArray(res.data.works) ? res.data.works.filter(function (w) { return w && w.id && w.artist; }) : [];
|
|
329
354
|
render();
|
|
355
|
+
changed();
|
|
330
356
|
if (first) { first = false; arrive(); }
|
|
331
357
|
}, function () { if (mine === asking) { list = []; render(); } });
|
|
332
358
|
}
|
|
@@ -348,7 +374,11 @@
|
|
|
348
374
|
root.hidden = !on;
|
|
349
375
|
if (on && !loaded) load();
|
|
350
376
|
if (!on && isFs()) setFs(false);
|
|
377
|
+
changed();
|
|
351
378
|
},
|
|
379
|
+
// task 1005211: the rows the visor shows for the gallery, and a hook for when they change
|
|
380
|
+
visorActions: visorActions,
|
|
381
|
+
onChange: function (fn) { changed = typeof fn === 'function' ? fn : function () {}; },
|
|
352
382
|
};
|
|
353
383
|
}
|
|
354
384
|
|
|
@@ -1587,15 +1587,28 @@ html.opt-window-open { overflow: hidden; }
|
|
|
1587
1587
|
|
|
1588
1588
|
/* THE CHARACTER (task 1005147). A builder who holds a character wears its sprite in
|
|
1589
1589
|
the top bar in place of the switch: one button, which offers "Change character"
|
|
1590
|
-
(signing out). The sprites are pixel art, so they scale by whole pixels.
|
|
1590
|
+
(signing out). The sprites are pixel art, so they scale by whole pixels.
|
|
1591
|
+
EACH CHARACTER HAS ONE COLOUR (task 1005218; --char-*): the Artisan's is the hall's own
|
|
1592
|
+
accent, the Artist's violet and the Patron's gold are the two colours the second look
|
|
1593
|
+
added, the same three the pictures are drawn in (docs/design/characters/v2). In game mode
|
|
1594
|
+
the visor wears the held character's (visor.css). */
|
|
1595
|
+
html {
|
|
1596
|
+
--char-artisan: var(--accent);
|
|
1597
|
+
--char-artist: color-mix(in oklch, color-mix(in oklch, var(--sea) 82%, var(--accent)) 72%, var(--ink));
|
|
1598
|
+
--char-patron: color-mix(in srgb, var(--warn) 72%, var(--ink));
|
|
1599
|
+
}
|
|
1591
1600
|
.craft-sprite { display: block; image-rendering: pixelated; object-fit: contain; }
|
|
1592
1601
|
.craft-switch__me { padding: 0 10px 0 4px; color: var(--ink); }
|
|
1593
|
-
/* The chip is the figure's head:
|
|
1594
|
-
.craft-sprite--chip { width: 26px; height: 26px; border-radius: var(--radius-pill); object-fit: cover;
|
|
1602
|
+
/* The chip is the figure's head: its own 32px picture. */
|
|
1603
|
+
.craft-sprite--chip { width: 26px; height: 26px; border-radius: var(--radius-pill); object-fit: cover; background: var(--bg-deep); }
|
|
1595
1604
|
/* Character creation: each door is the owner's portrait — the figure on its plinth
|
|
1596
1605
|
in the torch-lit hall — filling the top of the door, the words beneath it. */
|
|
1597
|
-
.craft-plinth { display: block; overflow: hidden; }
|
|
1598
|
-
.craft-sprite--door { width: 100%; height: auto; aspect-ratio:
|
|
1606
|
+
.craft-plinth { display: block; overflow: hidden; background: var(--bg-deep); }
|
|
1607
|
+
.craft-sprite--door { width: 100%; height: auto; aspect-ratio: 1; transition: transform var(--ds-dur-base) var(--ds-ease); }
|
|
1608
|
+
.craft-door--artisan { --char: var(--char-artisan); }
|
|
1609
|
+
.craft-door--artist { --char: var(--char-artist); }
|
|
1610
|
+
.craft-door--patron { --char: var(--char-patron); }
|
|
1611
|
+
.craft-door--character .craft-door__name { color: var(--char); }
|
|
1599
1612
|
.craft-door--character:hover .craft-sprite--door,
|
|
1600
1613
|
.craft-door--character:focus-visible .craft-sprite--door { transform: scale(1.03); }
|
|
1601
1614
|
|
|
@@ -18,6 +18,21 @@ html[data-game="on"] .visor:not([hidden]) {
|
|
|
18
18
|
color: var(--ink); font-family: var(--font-body);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
/* THE GLASS TAKES YOUR CHARACTER'S COLOUR (task 1005218). --char is the held character's one
|
|
22
|
+
colour (style.css --char-*): the frame's lines, the sight, your name and the rim of your
|
|
23
|
+
picture wear it, and the accent on the glass (the one button, the segment being built, a
|
|
24
|
+
hovered row) IS it, so nothing here names a colour of its own. The Artisan's is the hall's
|
|
25
|
+
accent, so an Artisan's glass is the accent it always was. */
|
|
26
|
+
.visor[data-character="artisan"] { --char: var(--char-artisan, var(--accent)); }
|
|
27
|
+
.visor[data-character="artist"] { --char: var(--char-artist, var(--accent)); }
|
|
28
|
+
.visor[data-character="patron"] { --char: var(--char-patron, var(--accent)); }
|
|
29
|
+
/* on the glass's parts, not the glass: --char reads the hall's accent above, so re-pointing
|
|
30
|
+
the accent on the same element would be a cycle */
|
|
31
|
+
.visor[data-character] > * {
|
|
32
|
+
--accent: var(--char); --accent-ink: var(--char);
|
|
33
|
+
--accent-lift: color-mix(in srgb, var(--char) 58%, var(--ink));
|
|
34
|
+
}
|
|
35
|
+
|
|
21
36
|
/* the frame: each arc is stretched across the stage, every stroke one hairline at any size. The
|
|
22
37
|
top arc, its notch and the place all sit inside the top inset, above where a scene starts its
|
|
23
38
|
own top row; the foot arc runs under the foot row. */
|
|
@@ -25,9 +40,9 @@ html[data-game="on"] .visor:not([hidden]) {
|
|
|
25
40
|
.visor__frame--top { top: calc(var(--visor-arc) - 50px); height: 42px; }
|
|
26
41
|
.visor__frame--foot { bottom: calc(var(--visor-inset-bottom) - 44px); height: 18px; }
|
|
27
42
|
.visor__frame path { vector-effect: non-scaling-stroke; }
|
|
28
|
-
.visor__line { fill: none; stroke: var(--ink-soft); stroke-opacity: .
|
|
43
|
+
.visor__line { fill: none; stroke: var(--char, var(--ink-soft)); stroke-opacity: .7; stroke-width: var(--line-strong); }
|
|
29
44
|
.visor__line--under { stroke: var(--bg); stroke-opacity: 1; stroke-width: 5px; }
|
|
30
|
-
.visor__dot { fill: var(--ink-soft); stroke: var(--bg); stroke-width: var(--line-strong); }
|
|
45
|
+
.visor__dot { fill: var(--char, var(--ink-soft)); stroke: var(--bg); stroke-width: var(--line-strong); }
|
|
31
46
|
.visor__notch, .visor__sight { position: absolute; left: 50%; transform: translate(-50%, -50%); overflow: visible; }
|
|
32
47
|
.visor__notch { top: calc(var(--visor-arc) - 36px); width: 12px; height: 9px; }
|
|
33
48
|
.visor__sight { top: 50%; width: 24px; height: 24px; }
|
|
@@ -76,12 +91,12 @@ html[data-game="on"] .visor:not([hidden]) {
|
|
|
76
91
|
transform: perspective(900px) rotateY(16deg); transform-origin: left center;
|
|
77
92
|
}
|
|
78
93
|
.visor__sprite {
|
|
79
|
-
flex: none; width: 56px; height: 56px; object-fit: cover;
|
|
80
|
-
background: var(--
|
|
94
|
+
flex: none; box-sizing: border-box; width: 56px; height: 56px; object-fit: cover; image-rendering: pixelated;
|
|
95
|
+
background: var(--bg-card); border: var(--line-strong) solid var(--char, var(--ink-soft)); clip-path: var(--cut-path-sm);
|
|
81
96
|
}
|
|
82
97
|
/* your name and credits stand in a box of the night, cut like the sprite beside it */
|
|
83
98
|
.visor__who { display: flex; flex-direction: column; gap: 2px; padding: var(--ds-space-hair) var(--ds-space-xs); }
|
|
84
|
-
.visor__name { font-size: var(--ds-text-xs); letter-spacing: var(--name-space); line-height: 1; color: var(--ink-soft); }
|
|
99
|
+
.visor__name { font-size: var(--ds-text-xs); letter-spacing: var(--name-space); line-height: 1; color: var(--char, var(--ink-soft)); }
|
|
85
100
|
.visor__credits { display: flex; align-items: baseline; gap: var(--ds-space-xs); white-space: nowrap; }
|
|
86
101
|
.visor__num { font-family: var(--name-face); font-size: var(--ds-text-headline); font-weight: 400; line-height: 1; color: var(--ink); font-variant-numeric: tabular-nums; }
|
|
87
102
|
.visor__unit { font-size: var(--ds-text-md); letter-spacing: var(--name-space); color: var(--ink-soft); }
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
// a small notch under the top arc and a ring-and-dot sight at the centre. Drawn as SVG;
|
|
8
8
|
// it is ornament, never a control.
|
|
9
9
|
// - the place, in the name voice under the top arc ("THE SKY", "GOVERNOR CITY", …).
|
|
10
|
-
// - the foot row. Left: your sprite (
|
|
10
|
+
// - the foot row. Left: your sprite (your character's head, wearing the visor, its rim in
|
|
11
|
+
// the character's colour; task 1005218), your character's name and your credits
|
|
11
12
|
// (builders.total_credits — credits only, never a payout; the spec's "does not exist").
|
|
12
13
|
// Centre: your character's main action, the one accent button, with its key. Right: the
|
|
13
14
|
// quiet key hints, no boxes: your other actions, "Actions" (key A), which opens the
|
|
@@ -189,14 +190,16 @@
|
|
|
189
190
|
}
|
|
190
191
|
function glassHtml(id) {
|
|
191
192
|
var acts = actionsFor(id), main = acts[0], C = craft();
|
|
192
|
-
|
|
193
|
+
// Your picture on the glass is you wearing the visor (task 1005218); an older craft-mode
|
|
194
|
+
// without that picture still hands over the whole figure.
|
|
195
|
+
var sprite = C && typeof C.portraitSrc === 'function' ? C.portraitSrc(id) : (C && typeof C.spriteSrc === 'function' ? C.spriteSrc(id) : '');
|
|
193
196
|
var n = credits();
|
|
194
197
|
return frameSvg() +
|
|
195
198
|
(scene.place ? '<p class="visor__place">' + esc(scene.place) + '</p>' : '') +
|
|
196
199
|
progressHtml() +
|
|
197
200
|
'<div class="visor__foot">' +
|
|
198
201
|
'<div class="visor__me">' +
|
|
199
|
-
(sprite ? '<img class="visor__sprite" src="' + esc(sprite) + '" alt="" width="
|
|
202
|
+
(sprite ? '<img class="visor__sprite" src="' + esc(sprite) + '" alt="" width="32" height="32" decoding="async">' : '') +
|
|
200
203
|
'<span class="visor__who"><span class="visor__name">' + esc(NAMES[id]) + '</span>' +
|
|
201
204
|
'<span class="visor__credits" data-visor-credits>' + creditsHtml(n) + '</span></span>' +
|
|
202
205
|
'</div>' +
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# The characters — the three pictures, their colours, and where each is worn (task 1005218; ADR 0405)
|
|
2
|
+
|
|
3
|
+
Covers: `public/characters/*.png`, the character parts of `craft-mode.js` (creation doors, the top-bar chip), the `--char-*` tokens in `style.css`, and the character's colour on the visor (`visor.css`). The visor itself is in `visor.md`; character creation's behaviour is task 1005147's and is unchanged.
|
|
4
|
+
|
|
5
|
+
## What it settled
|
|
6
|
+
|
|
7
|
+
- **The second look.** 64 by 64 pixel art, two animals in one body, as aliens in the Helm night. One animal gives the whole head, the other the whole body: Artisan a ram on a lizard with the long spanner, Artist an ibis on an octopus with the light-brush, Patron a falcon on a lion with the staff of office. They stand three-quarters to the viewer on a lit disc. The six rules the owner's feedback set (recognisable animals, not childish, a role tool, a 2.5D stance, simple shapes, one light) are the header of the drawing script.
|
|
8
|
+
- **The pictures are drawn, never edited.** `node docs/design/characters/v2/draw-characters.js --hall` writes all nine files: `<id>.png` (the whole figure, 64 by 64: the creation doors), `<id>-face.png` (the head, 32 by 32: the top-bar chip) and `<id>-visor.png` (the head wearing the visor, 32 by 32: the visor's corner). `craft-mode.js` hands them out as `spriteSrc`, `faceSrc` and `portraitSrc`.
|
|
9
|
+
- **One colour each** (`style.css`, on `html`, beside the sprite rules): `--char-artisan` is the accent, `--char-artist` a violet and `--char-patron` a gold, both mixed from the hall's own tokens (ADR 0405 §2). No colour is typed in.
|
|
10
|
+
- **Where the colour is worn.** The creation door's name; and, in game mode, the visor: `.visor[data-character]` sets `--char` and re-points `--accent`, `--accent-ink` and `--accent-lift` at it, so the frame's lines, the sight, the name, the picture's rim, the one button and the segment being built all follow with no rule of their own. An Artisan's glass is exactly what it was.
|
|
11
|
+
- **Pixel art scales by nearest pixel** (`image-rendering: pixelated`) everywhere a picture is shown.
|
|
12
|
+
|
|
13
|
+
## Not done
|
|
14
|
+
|
|
15
|
+
- A scene's own buttons keep the hall's accent under a violet or gold glass (the Governor City's "decide" button). ADR 0403's follow-up tasks move them to the visor.
|
|
16
|
+
- The visor shows the 32px head at 56px (36px on a phone), which is not a whole multiple, so a few pixels are uneven.
|
|
17
|
+
- The pictures keep their own fixed colours when a host re-themes its accent.
|
|
18
|
+
|
|
19
|
+
Tests: `tests/character_creation.mjs` (the nine files, their sizes, the chip's picture) and `tests/hall_visor.mjs` (the portrait, the colour on the glass per character).
|