Si comincia svegliandosi sulla panchina dei vecchietti dopo una notte brava: gli occhi che si aprono a fatica, la piazza sfocata e doppia; e dal Barone il telefonino col sito di San Piero, che si apre a tutto schermo, e il Muro del Sanpierino vero coi messaggi del 2007, «Aggiorna» compreso (Andrea)

- Il risveglio (src/engine/risveglio.js): primo piano sopra la scena, con le battute mentre le palpebre si aprono e
  i vecchietti che danno la notizia del palio; «Salta» lo salta.
- Il telefonino del Barone (src/engine/telefono.js): sale dal basso come il libro, la home di sanpiero50037.it dalla
  Wayback Machine nello schermo, il mattone del muro apre il muro.
- Il muro (assets/muro, tools/muro.py): la pagina vera rifatta statica dal muro riesumato, coi 24 messaggi del dump
  (senza email né IP) e quelli del gioco, che arrivano con la storia; «Scrivi» spento.
- Il gioco sgancia i service worker di altre app rimasti sul suo indirizzo (la Bussola su localhost:8080).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GiECd9RWGMKV7n3K1mdy8T
This commit is contained in:
2026-10-31 09:52:34 +01:00
co-authored by Claude Opus 5.5
parent 1ea78161d1
commit c5953f04c0
93 changed files with 1112 additions and 68 deletions
+57
View File
@@ -0,0 +1,57 @@
// Il Muro del Sanpierino sul telefonino del Barone, nel browser vero: il telefonino che sale, il sito a tutto
// schermo, il clic sul mattone del muro. npm run browser:telefono — schermate in /tmp/regolo-telefono.
import { chromium } from 'playwright';
import { mkdirSync } from 'node:fs';
import assert from 'node:assert/strict';
import { staticServer } from './helpers.mjs';
const out = process.env.OUT ?? '/tmp/regolo-telefono';
mkdirSync(out, { recursive: true });
const server = await staticServer();
let browser;
const errors = [];
try {
browser = await chromium.launch({ args: ['--autoplay-policy=no-user-gesture-required', '--use-gl=angle', '--use-angle=swiftshader', '--enable-unsafe-swiftshader'] });
const page = await browser.newPage({ viewport: { width: 1280, height: 860 } });
page.on('pageerror', e => { errors.push(e.message); console.log('ERR', e.message); });
await page.goto(`http://127.0.0.1:${server.port}/`);
await page.click('#splash'); await page.click('#new-game'); await page.click('#rione [data-rione="campomigliaio"]'); await page.click('#skip-intro');
await page.evaluate(async () => {
const { settle } = await import('/tests/helpers.mjs');
settle(game); game.go('polisportiva'); settle(game);
game.act('talk', 'barondeduke'); settle(game);
game.choose(game.options().findIndex(o => o.text.includes('muro del Sanpierino'))); settle(game);
});
await page.waitForFunction(() => game.closeup?.id === 'muro_sanpierino' && game.closeup.age > 1.2, null, { timeout: 15000 });
await page.screenshot({ path: `${out}/1-telefonino.png` });
const box = await page.locator('#scene').boundingBox(), k = box.width / 640;
const click = ([x, y]) => page.mouse.click(box.x + x * k, box.y + y * k);
await click([320, 180]);
await page.waitForFunction(() => game.closeup.step === 'site', null, { timeout: 5000 });
await page.waitForTimeout(300);
await page.screenshot({ path: `${out}/2-sito.png` });
const link = await page.evaluate(async () => { const t = await import('/src/engine/telefono.js'); const d = story => story.closeups.muro_sanpierino; const def = d(game.story); const [x, y, w, h] = t.linkBox(def, def.siteSize); return [x + w / 2, y + h / 2]; });
await click(link);
await page.waitForFunction(() => game.closeup.step === 'wall', null, { timeout: 8000 });
// Il muro è la pagina vera: i messaggi del gioco in cima, sotto quelli del 2007; «Scrivi» spento, niente email.
const frame = page.frameLocator('#muro');
await frame.locator('.name').first().waitFor({ timeout: 10000 });
assert.match(await frame.locator('.name').first().textContent(), /Il Regolo/);
assert.ok((await frame.locator('.name').allTextContents()).some(t => t.includes('Kiara')), 'i messaggi veri del 2007');
assert.match(await frame.locator('.pagerbutton', { hasText: 'SCRIVI' }).first().getAttribute('class'), /disabled/);
assert.equal(await frame.locator('a[href^="mailto:"]').count(), 0);
await page.waitForTimeout(500);
await page.screenshot({ path: `${out}/3-muro.png` });
// La storia va avanti: «Aggiorna» fa comparire il messaggio nuovo.
await page.evaluate(() => { game.speech = null; game.closeup.lines = []; game.state.flags.indizio_regolo = true; });
await frame.locator('.pagerbutton', { hasText: 'Aggiorna' }).first().click();
await page.waitForTimeout(800);
assert.match(await frame.locator('.name').first().textContent(), /Uno che passava/);
await page.screenshot({ path: `${out}/4-aggiornato.png` });
// «Home» torna alla home del sito sul telefonino.
await frame.locator('.pagerbutton', { hasText: 'Home' }).first().click();
await page.waitForFunction(() => game.closeup.step === 'site', null, { timeout: 5000 });
await page.waitForSelector('#muro', { state: 'hidden', timeout: 3000 });
assert.deepEqual(errors, []);
console.log(`ok: schermate in ${out}`);
} finally { await browser?.close(); server.kill(); }