@bongos/core 1.25.6 → 1.25.7
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 +37 -27
- package/docs/copy-inventory.md +9 -8
- package/docs/copy-registry.json +20 -11
- package/docs/module-api-changelog.md +2 -2
- package/docs/page-readings.json +37 -37
- package/modules/hall-ui/public/shell-game.js +98 -2
- package/modules/hall-ui/public/style.css +59 -0
- package/modules/hall-ui/public/visor.css +11 -0
- package/modules/hall-ui/public/visor.js +14 -5
- package/modules/hall-ui/records/game-menu.md +22 -0
- package/modules/hall-ui/records/game-mode.md +2 -2
- package/modules/hall-ui/records/options-menu.md +1 -1
- package/modules/hall-ui/records/start-screen.md +2 -2
- package/modules/hall-ui/records/visor.md +4 -0
- package/modules/ui-design/public/brand.html +1 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +16 -1
- package/src/module-api.js +1 -1
- package/tests/hall_game_menu.mjs +195 -0
- package/tests/hall_options_menu.mjs +4 -1
- package/tests/hall_visor.mjs +40 -5
package/tests/hall_visor.mjs
CHANGED
|
@@ -105,8 +105,8 @@ test('no key ever means two things: every character over every real scene, and O
|
|
|
105
105
|
assert.notEqual(r.options.key, 'esc', `${c}: Options is not on Escape; Escape is Close`);
|
|
106
106
|
assert.ok(r.options.key, `${c}: Options has a key of its own`);
|
|
107
107
|
}
|
|
108
|
-
assert.equal(V.resolveKeys('artist').options.key, '
|
|
109
|
-
assert.equal(V.resolveKeys('patron').options.key, '
|
|
108
|
+
assert.equal(V.resolveKeys('artist').options.key, 'm', 'M is the game menu where nothing else holds it');
|
|
109
|
+
assert.equal(V.resolveKeys('patron').options.key, 'm', 'no character holds M, so the game menu keeps it for all three');
|
|
110
110
|
});
|
|
111
111
|
|
|
112
112
|
test('a clash moves the later claimant to a free letter of its own name, and its key follows', () => {
|
|
@@ -205,6 +205,25 @@ test('source: the minimal visor spends the Helm tokens and types in no colour, s
|
|
|
205
205
|
assert.doesNotMatch(glass, /background|box-shadow|backdrop-filter|filter:/, 'the glass itself paints nothing: no edge band, no vignette, no veil');
|
|
206
206
|
assert.doesNotMatch(css, /--night-glass|linear-gradient|radial-gradient\((?!circle, currentColor)|--type-halo/, 'no band of the night anywhere on the glass, and no dark glow round its type');
|
|
207
207
|
assert.match(css, /\.visor__place, \.visor__who, \.visor__hint \{ background: var\(--night-plate\); clip-path: var\(--cut-path-sm\); \}/, 'the place, each hint and your credits stand on a small cut plate of the night');
|
|
208
|
+
// smoked glass (task 1005252): where the browser can blur, each plate is a pane that softens the scene
|
|
209
|
+
// behind it, from the Helm tokens; asking for less transparency puts the night plate back
|
|
210
|
+
const PANES = '.visor__place, .visor__who, .visor__hint, .visor__progress-words {';
|
|
211
|
+
const block = (head) => { const at = css.indexOf(head); assert.ok(at >= 0, head); const open = css.indexOf(PANES, at); assert.ok(open > at, head + ' holds the four plates'); return css.slice(open, css.indexOf('}', open)); };
|
|
212
|
+
const smoke = block('@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {');
|
|
213
|
+
assert.ok(smoke.includes('background: var(--smoke-sheen), var(--smoke);'), 'a light smoke with a sheen, from tokens');
|
|
214
|
+
assert.ok(smoke.includes('box-shadow: var(--smoke-edge);'), 'a lit top edge makes it a pane');
|
|
215
|
+
assert.ok(smoke.includes(' backdrop-filter: var(--smoke-blur);'), 'it blurs the scene behind it');
|
|
216
|
+
const STYLE = fs.readFileSync(new URL('../modules/hall-ui/public/style.css', import.meta.url), 'utf8');
|
|
217
|
+
const plainAt = STYLE.indexOf('@media (prefers-reduced-transparency: reduce) {');
|
|
218
|
+
const plain = STYLE.slice(plainAt, STYLE.indexOf('}', plainAt));
|
|
219
|
+
assert.ok(plainAt >= 0 && plain.includes('html .visor__place, html .visor__who, html .visor__hint, html .visor__progress-words {'), 'less transparency is answered in style.css, lifted over visor.css');
|
|
220
|
+
assert.ok(plain.includes('background: var(--night-plate);') && plain.includes(' backdrop-filter: none;'), 'less transparency: the night plate again');
|
|
221
|
+
const smokeTokens = STYLE.match(/--smoke[a-z-]*:[^;]*;/g) || [];
|
|
222
|
+
assert.equal(smokeTokens.length, 4, 'four smoke tokens: the tint, the blur, the sheen, the edge');
|
|
223
|
+
assert.doesNotMatch(smokeTokens.join(' '), /rgba?\(|#[0-9a-f]{3,8}\b/i, 'every smoke colour derives from a Helm token, no literal');
|
|
224
|
+
assert.ok(STYLE.includes('html[data-game="on"] .visor__who, html[data-game="on"] .visor__hint { background: var(--night-plate); box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none; }'), 'a phone keeps the night plate: no live blur on the weakest GPU');
|
|
225
|
+
assert.ok(STYLE.indexOf('backdrop-filter: none; }') > STYLE.indexOf('tasks 1005148 and 1005195, the visor'), 'and that rule sits in the shared phone block');
|
|
226
|
+
assert.ok(css.indexOf('@supports ((backdrop-filter') > css.indexOf('.visor__progress-words {'), 'the smoke comes after every plate rule, so it wins the cascade');
|
|
208
227
|
assert.match(css, /\.visor__line--under \{ stroke: var\(--bg\); stroke-opacity: 1/, 'every line is drawn over a solid stroke of the night, so it reads on cloud and on night');
|
|
209
228
|
assert.match(css, /\.visor__key \{[^}]*background: var\(--bg\)/, 'a key sits on a chip of the night');
|
|
210
229
|
assert.doesNotMatch(css, /data-hour|data-time|data-sky/, 'no per-hour style');
|
|
@@ -365,12 +384,26 @@ test('a lead scene action is the first key hint, and its click and its key run i
|
|
|
365
384
|
await ctx.close();
|
|
366
385
|
});
|
|
367
386
|
|
|
387
|
+
// task 1005251: the options window keeps its aria-modal box after it closes. Only a dialog that
|
|
388
|
+
// is SHOWN holds the visor's keys; before this, one visit to Options left every key dead.
|
|
389
|
+
test('a closed dialog left in the page does not hold the keys; an open one does', { skip }, async () => {
|
|
390
|
+
const { ctx, page } = await open();
|
|
391
|
+
await page.evaluate(() => { const d = document.createElement('div'); d.id = 'gone'; d.setAttribute('aria-modal', 'true'); d.hidden = true; document.body.appendChild(d); });
|
|
392
|
+
await page.keyboard.press('a');
|
|
393
|
+
assert.equal(await page.evaluate(() => OTBVisor.isOpen()), true, 'a hidden modal box: A still opens the sheet');
|
|
394
|
+
await page.keyboard.press('Escape');
|
|
395
|
+
await page.evaluate(() => { document.getElementById('gone').hidden = false; document.getElementById('gone').textContent = 'up'; });
|
|
396
|
+
await page.keyboard.press('a');
|
|
397
|
+
assert.equal(await page.evaluate(() => OTBVisor.isOpen()), false, 'a modal that is up keeps the keyboard');
|
|
398
|
+
await ctx.close();
|
|
399
|
+
});
|
|
400
|
+
|
|
368
401
|
test('the sheet lists the character\'s actions, then this place, and runs a scene action', { skip }, async () => {
|
|
369
402
|
const { ctx, page } = await open();
|
|
370
403
|
await page.click('[data-visor-sheet]');
|
|
371
404
|
const rows = await page.$$eval('.visor__sheet .visor__row', (r) => r.map((x) => [...x.children].map((c) => c.textContent).join(' ')));
|
|
372
405
|
// task 1005200: Claim a task and Blockers open classic pages, so they are off the glass.
|
|
373
|
-
assert.deepEqual(rows, ['Goal sky G', 'Your thinking T', 'Back to centre 0', 'Look around drag', '
|
|
406
|
+
assert.deepEqual(rows, ['Goal sky G', 'Your thinking T', 'Back to centre 0', 'Look around drag', 'Game menu M']);
|
|
374
407
|
assert.equal(await page.$eval('.visor__sheet [data-visor-close]', (b) => b.textContent), 'Esc', 'Escape is the Close of the sheet, and only that');
|
|
375
408
|
await page.click('[data-visor-scene="0"]');
|
|
376
409
|
assert.deepEqual(await page.evaluate(() => ({ centred: window.centred, open: OTBVisor.isOpen() })), { centred: true, open: false });
|
|
@@ -481,7 +514,7 @@ test('the glass is the kit\'s: the cut accent button, ice hints with no box, the
|
|
|
481
514
|
return {
|
|
482
515
|
mainBg: cs('.visor__main').backgroundColor, accent: probe('var(--accent)'), mainClip: cs('.visor__main').clipPath,
|
|
483
516
|
mainCase: cs('.visor__main').textTransform, hintBg: cs('.visor__hint').backgroundColor, hintBorder: cs('.visor__hint').borderTopWidth,
|
|
484
|
-
plate: probe('var(--
|
|
517
|
+
plate: probe('var(--smoke)'), blur: cs('.visor__place').backdropFilter, edge: cs('.visor__hint').boxShadow, placeBg: cs('.visor__place').backgroundColor, whoBg: cs('.visor__who').backgroundColor, hintClip: cs('.visor__hint').clipPath,
|
|
485
518
|
glassBg: cs('#visor').backgroundImage + ' ' + cs('#visor').backgroundColor,
|
|
486
519
|
hintColor: cs('.visor__hint').color, ice: probe('var(--ink-soft)'), num: cs('.visor__num').color, unit: cs('.visor__unit').color, white: probe('var(--ink)'),
|
|
487
520
|
placeShadow: cs('.visor__place').textShadow, radius: cs('.visor__sprite').borderTopLeftRadius, spriteClip: cs('.visor__sprite').clipPath,
|
|
@@ -492,7 +525,9 @@ test('the glass is the kit\'s: the cut accent button, ice hints with no box, the
|
|
|
492
525
|
assert.match(g.mainClip, /^polygon\(/, 'cut corner');
|
|
493
526
|
assert.equal(g.mainCase, 'uppercase', 'the name voice');
|
|
494
527
|
assert.equal(g.glassBg, 'none rgba(0, 0, 0, 0)', 'the glass darkens nothing: the scene shows to every edge');
|
|
495
|
-
assert.equal(g.hintBg, g.plate, 'a hint stands on a
|
|
528
|
+
assert.equal(g.hintBg, g.plate, 'a hint stands on a pane of smoked glass (task 1005252)');
|
|
529
|
+
assert.match(g.blur, /blur\(14px\)/, 'the pane blurs the scene behind it');
|
|
530
|
+
assert.match(g.edge, /inset/, 'and has a lit edge');
|
|
496
531
|
assert.equal(g.placeBg, g.plate, 'so does the place');
|
|
497
532
|
assert.equal(g.whoBg, g.plate, 'and your credits');
|
|
498
533
|
assert.match(g.hintClip, /^polygon\(/, 'the plate is cut');
|