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
+7 -5
View File
@@ -13,7 +13,8 @@ const voci = JSON.parse(readFileSync(new URL('../tools/voci.json', import.meta.u
test('le battute si trovano ovunque: introduzione, scene, oggetti, dialoghi e rami if', () => {
const lines = voiceLines(story), has = (who, part) => lines.some(l => l.who === who && l.text.includes(part));
assert.ok(has('andrea', 'Fine maggio 2007'), 'introduzione');
assert.ok(has('andrea', 'Il palio è sparito!'), 'ingresso in una scena, dentro un if');
assert.ok(has('vecchietto', 'Il palio è sparito!'), 'primo piano del risveglio, a occhi aperti');
assert.ok(has('andrea', 'che botta'), 'primo piano del risveglio, mentre gli occhi si aprono');
assert.ok(has('vecchietta', 'cadde dal cielo'), 'dialogo, con chi parla');
assert.ok(has('castello', 'vicino alle sue impronte'), 'ramo else annidato');
assert.ok(has('andrea', 'pagina sola'), 'azione di un oggetto');
@@ -61,15 +62,16 @@ test('il castello e il leone hanno voci diverse da tutti gli altri', () => {
});
test('il fumetto resta a schermo almeno quanto la voce', () => {
const g = new Game(story, { voiceTime: (who, text) => (text.startsWith('Il palio') ? 9 : undefined) });
// La prima battuta della partita è quella del risveglio, mentre gli occhi si aprono.
const g = new Game(story, { voiceTime: (who, text) => (text.startsWith('Mmmh') ? 9 : undefined) });
g.go(story.start.scene, story.start.at);
g.update(0.05);
assert.ok(g.speech.text.startsWith('Il palio'));
for (let i = 0; i < 40 && !g.speech; i++) g.update(0.05);
assert.ok(g.speech.text.startsWith('Mmmh'));
assert.ok(g.speech.left > 9, 'la voce lunga allunga il fumetto');
settle(g);
const quiet = new Game(story);
quiet.go(story.start.scene, story.start.at);
quiet.update(0.05);
for (let i = 0; i < 40 && !quiet.speech; i++) quiet.update(0.05);
assert.ok(quiet.speech.left < 9, 'senza voce vale la durata di lettura');
});