Forno, stazione e chiesa; uscite della rotonda e di Via Calimara come il paese vero; mappa ordinata

- Dalla Pieve a destra il forno e, a sinistra, la stazione; dal portone centrale si entra nella Pieve
  (foto di Mariano Mirannalti, nei crediti alla voce «Fotografie»).
- Via Calimara: in fondo la Piazza, verso chi guarda la farmacia. Rotonda del River: a sinistra il campo
  sportivo, in basso l'area feste, dietro la farmacia la Pieve, a destra il Comune, in basso a destra Calimara.
- Polisportiva: dal ponte prima il campo principale, poi il secondario col padel; dietro, l'area feste.
- Andrea ha 27 anni nel 2007: battute, documento e CLAUDE.md corretti.
- Mappa su una griglia ordinata, senza etichette sovrapposte.
- Doppio clic: Andrea va al doppio della velocità. In pausa la musica sfuma e si ferma; dopo un minuto
  senza toccare niente il gioco va in pausa da solo.
- Crediti: scorre solo l'elenco, dedica e Chiudi sempre in vista.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017egeN2amL84ErjfgQFtEDn
This commit is contained in:
2026-10-23 20:00:28 +02:00
co-authored by Claude Opus 5.5
parent 043a5abdcb
commit 2d682d8ae9
53 changed files with 341 additions and 93 deletions
+18 -2
View File
@@ -10,7 +10,10 @@ import { Voices } from './engine/voices.js';
const $ = id => document.getElementById(id);
const canvas = $('scene'), ctx = canvas.getContext('2d');
const storage = (() => { try { return window.localStorage; } catch { return null; } })();
const LONG_PRESS = 450;
const LONG_PRESS = 450, DOUBLE_CLICK = 350, IDLE_PAUSE = 60000;
let idleSince = performance.now();
for (const ev of ['pointerdown', 'pointermove', 'keydown', 'wheel']) addEventListener(ev, () => { idleSince = performance.now(); }, { capture: true, passive: true });
let lastTap = null;
const debug = new URLSearchParams(location.search).has('debug');
let game = null, command = null, hoverTarget = null, mouse = null, running = false;
@@ -106,12 +109,16 @@ $('map-button').addEventListener('click', openMap);
function openPause() {
if (!running) return;
running = false;
music.hold = true;
voices.stop();
command.reset();
$('pause-map').hidden = game.mapPlaces().length < 2;
$('pause').hidden = false;
}
function closePause() {
$('pause').hidden = true;
music.hold = false;
idleSince = performance.now();
running = true;
}
$('pause-button').addEventListener('click', openPause);
@@ -119,6 +126,7 @@ $('resume').addEventListener('click', closePause);
$('pause-map').addEventListener('click', () => { closePause(); openMap(); });
$('to-title').addEventListener('click', () => {
$('pause').hidden = true;
music.hold = false;
game.onSave(game.snapshot());
showTitle();
});
@@ -145,7 +153,13 @@ canvas.addEventListener('pointerdown', e => {
canvas.addEventListener('pointerup', e => {
if (!press) return;
clearTimeout(press.timer);
if (!press.long) command.clickScene(scenePoint(e));
// Il secondo clic vicino al primo, entro poco, è un doppio clic: stesso comando, al doppio della velocità.
if (!press.long) {
const point = scenePoint(e), now = performance.now();
const hurry = !!lastTap && now - lastTap.time < DOUBLE_CLICK && Math.hypot(point[0] - lastTap.point[0], point[1] - lastTap.point[1]) < 24;
command.clickScene(point, { hurry });
lastTap = hurry ? null : { time: now, point };
}
press = null;
});
canvas.addEventListener('pointercancel', () => { if (press) clearTimeout(press.timer); press = null; });
@@ -281,6 +295,8 @@ function frame(now) {
const screen = !$('title').hidden ? 'title' : !$('splash').hidden ? 'splash' : !$('intro').hidden ? 'intro' : !$('ending').hidden ? 'ending' : 'game';
music.duck = voices.playing ? 0.45 : 1;
music.update(trackFor(story, { screen, scene: game?.state.scene }), dt);
// Un minuto senza toccare niente, a gioco fermo: pausa da sola.
if (running && now - idleSince > IDLE_PAUSE && !game.speech && !game.walking && !game.queue.length) openPause();
if (game) {
if (running) game.update(dt);
render(ctx, game, { hover: debug && hoverTarget ? game.hotspot(hoverTarget) : null });