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
+3 -2
View File
@@ -26,9 +26,10 @@ export class Command {
return isItem ? `Usa ${name} con…` : `${VERB_LABELS[g.defaultVerb(target)]} ${name}`;
}
// Clic sulla scena: `look` per il clic destro o la pressione lunga.
clickScene(point, { look = false } = {}) {
// Clic sulla scena: `look` per il clic destro o la pressione lunga, `hurry` per il doppio clic (passo doppio).
clickScene(point, { look = false, hurry = false } = {}) {
const g = this.game;
g.hurry = hurry;
if (g.skip()) return 'skip';
if (g.dialogue || g.busy) return null;
const h = g.hotspotAt(point);
+2 -1
View File
@@ -62,6 +62,7 @@ export class Game {
this.walking = false;
this.time = 0;
this.stride = 0; // strada fatta, per scegliere il passo della camminata
this.hurry = false; // doppio clic: si cammina al doppio della velocità
this.reach = 0; // secondi di braccio teso quando prende qualcosa
this.back = false; // di spalle davanti a una porta o a una bacheca
}
@@ -213,7 +214,7 @@ export class Game {
}
if (this.walking) {
const scale = this.scaleAt(this.state.y);
let step = SPEED * scale * dt;
let step = SPEED * (this.hurry ? 2 : 1) * scale * dt;
this.stride += step / scale;
while (step > 0 && this.path.length) {
const target = this.path[0], d = dist([this.state.x, this.state.y], target);
+4 -1
View File
@@ -23,6 +23,7 @@ export class Music {
this.current = null; // { src, audio }
this.old = [];
this.duck = 1; // 1 = pieno; meno di 1 mentre parla qualcuno
this.hold = false; // in pausa: il brano sfuma e si ferma, poi riprende da dov'era
}
// Chiamata a ogni fotogramma con il brano voluto: avvia, cambia e sfuma.
@@ -33,10 +34,12 @@ export class Music {
this.current = src ? { src, audio: this.start(src) } : null;
}
// Il brano in corso sale (o scende) verso il volume scelto; quelli vecchi sfumano fino a zero.
const step = dt / FADE, target = this.muted ? 0 : this.volume * this.duck;
const step = dt / FADE, target = this.muted || this.hold ? 0 : this.volume * this.duck;
if (this.current) {
const a = this.current.audio;
a.volume = a.volume < target ? Math.min(target, a.volume + step) : Math.max(target, a.volume - step);
if (this.hold && a.volume === 0 && !a.paused) a.pause();
else if (!this.hold && a.paused && a !== this.blocked) a.play().catch(() => { this.blocked = a; });
}
for (const a of this.old) a.volume = Math.max(0, a.volume - step);
this.old = this.old.filter(a => a.volume > 0 || (a.pause(), false));
+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 });
+167 -49
View File
@@ -24,6 +24,8 @@ export const story = {
{ role: 'Storia e aneddoti di San Piero', names: ['Francesco Bacci'] },
{ role: 'Musica', names: ['Andrea Manzi, con Suno'] },
{ role: 'Sfondi', names: ['dalle fotografie di San Piero di Andrea'] },
// Chi ci ha mandato foto, ricordi o idee: una riga per contributo, si allunga man mano.
{ role: 'Fotografie', names: ['Mariano Mirannalti (l\'interno della Pieve)'] },
{ role: 'Voci', names: ['XTTS-v2 di Coqui'] },
{ role: 'Programmazione', names: ['Andrea Manzi, con Claude e Codex'] },
],
@@ -72,7 +74,7 @@ export const story = {
scenes: {
piazza: {
name: 'Piazza Colonna',
map: [16, 70],
map: [32, 45],
background: 'assets/scenes/piazza-colonna.png',
walk: [[84, 244], [330, 238], [345, 230], [362, 238], [462, 246], [466, 276], [544, 276], [548, 248], [588, 250], [600, 290], [640, 300], [640, 360], [0, 360], [0, 330], [84, 318]],
depth: [[236, 0.5], [360, 1.35]],
@@ -150,7 +152,7 @@ export const story = {
id: 'verso_comune', name: 'a sinistra, verso il Comune', box: [96, 196, 50, 54], at: [120, 252], exit: { scene: 'comune', at: [20, 300], face: 'right' },
},
{
id: 'verso_calimara', name: 'Via Calimara, verso la farmacia', box: [180, 334, 380, 26], at: [360, 354], exit: { scene: 'via_calimara', at: [300, 350], face: 'up' },
id: 'verso_calimara', name: 'Via Calimara, verso la farmacia', box: [180, 334, 380, 26], at: [360, 354], exit: { scene: 'via_calimara', at: [365, 212], face: 'down' },
},
{
id: 'verso_pieve', name: 'verso la Pieve', box: [612, 292, 28, 68], at: [628, 330], exit: { scene: 'pieve', at: [30, 320], face: 'right' },
@@ -160,7 +162,7 @@ export const story = {
},
fortezza: {
name: 'Sotto le mura della Fortezza',
map: [30, 15],
map: [36, 6],
background: 'assets/scenes/fortezza-esterno.png',
walk: [[110, 284], [300, 280], [330, 272], [348, 274], [400, 292], [442, 294], [640, 352], [640, 360], [0, 360], [0, 315], [60, 310], [105, 295]],
depth: [[272, 0.55], [360, 1.15]],
@@ -211,7 +213,7 @@ export const story = {
// Livello 0: la Pieve vista dalla salita, con la salita per Villa Adami alle spalle.
pieve: {
name: 'La Pieve',
map: [46, 70],
map: [56, 45],
background: 'assets/scenes/pieve-dalla-salita.png',
speakers: { san_pietro: [343, 166] },
// La rampa in primo piano e, dietro il muretto, il sagrato (ci si arriva da sinistra).
@@ -226,6 +228,9 @@ export const story = {
open: [{ say: 'Il prete è a benedire le carrette del Palio. Torno dopo.' }],
},
},
{
id: 'portone', name: 'portone della Pieve', box: [196, 160, 46, 56], at: [218, 222], face: 'up', exit: { scene: 'pieve_interno', at: [320, 352], face: 'up' },
},
{
id: 'campanile', name: 'campanile', box: [272, 8, 60, 140], at: [300, 300], face: 'up',
actions: {
@@ -277,20 +282,63 @@ export const story = {
},
},
{
id: 'verso_provinciale', name: 'Via Provinciale, verso il River', box: [30, 330, 200, 30], at: [130, 350], exit: { scene: 'via_provinciale', at: [100, 350], face: 'up' },
id: 'verso_provinciale', name: 'Via Provinciale, verso il River', box: [30, 330, 200, 30], at: [130, 350], exit: { scene: 'via_provinciale', at: [560, 240], face: 'left' },
},
{
id: 'verso_piazza', name: 'verso la Piazza', box: [0, 262, 26, 98], at: [8, 320], exit: { scene: 'piazza', at: [610, 320], face: 'left' },
},
{
id: 'verso_forno', name: 'a destra, verso il forno', box: [570, 176, 70, 76], at: [588, 250], exit: { scene: 'forno', at: [40, 330], face: 'right' },
},
{
id: 'salita_villa_adami', name: 'salita verso Villa Adami', box: [440, 330, 200, 30], at: [600, 350], exit: { scene: 'villa_adami', at: [595, 268], face: 'left' },
},
],
},
// Dentro la Pieve (dalla foto di Mariano Mirannalti): la navata, l'altare, il crocifisso e San Pietro.
pieve_interno: {
name: 'Dentro la Pieve',
map: [56, 39],
background: 'assets/scenes/pieve-interno.png',
walk: [[262, 360], [290, 256], [350, 256], [380, 360]],
depth: [[256, 0.5], [360, 1.15]],
entry: [320, 352],
hotspots: [
{
id: 'altare', name: 'altare', box: [270, 186, 100, 64], at: [320, 262], face: 'up',
actions: {
look: [{ say: 'L\'altare, coi candelieri dorati e i fiori freschi. Qualcuno li cambia ogni mattina, prima di tutti.' }],
take: [{ say: 'Un candeliere? Mi sa che San Pietro le chiavi del Paradiso me le toglie per sempre.' }],
},
},
{
id: 'crocifisso', name: 'crocifisso', box: [296, 100, 48, 70], at: [320, 262], face: 'up',
actions: {
look: [{ say: 'Il grande crocifisso di legno, davanti alla statua di San Pietro.' }, { say: 'Qui si abbassa la voce senza che nessuno lo chieda.' }],
},
},
{
id: 'san_pietro_statua', name: 'statua di San Pietro', box: [298, 64, 44, 40], at: [320, 262], face: 'up',
actions: {
look: [{ say: 'San Pietro, il patrono. Quello fuori sul sagrato parla. Questo, per fortuna, no.' }],
},
},
{
id: 'panche', name: 'panche', box: [0, 240, 250, 120], at: [280, 320], face: 'left',
actions: {
look: [{ say: 'Le panche dove ci siamo seduti tutti, dal battesimo in poi. Le più scomode del Mugello.' }],
use: [{ say: 'Un minuto seduto... no, se mi siedo qui mi addormento come alla messa delle undici.' }],
},
},
{
id: 'uscita', name: 'esci sul sagrato', box: [240, 334, 160, 26], at: [320, 356], exit: { scene: 'pieve', at: [218, 222], face: 'down' },
},
],
},
// Il cortile dell'oratorio, dietro la porta della canonica: palco, tettoia, tavolate della festa.
oratorio: {
name: 'Oratorio della Pieve',
map: [74, 70],
map: [82, 45],
background: 'assets/scenes/oratorio.png',
walk: [[0, 236], [300, 226], [480, 222], [500, 232], [640, 254], [640, 360], [0, 360]],
depth: [[222, 0.5], [360, 1.15]],
@@ -340,7 +388,7 @@ export const story = {
// Via de' Medici: dalla Piazza sale verso Villa Adami (la Piazza è alle spalle, in fondo si va su).
via_de_medici: {
name: 'Via de\' Medici',
map: [14, 52],
map: [22, 32],
background: 'assets/scenes/via-de-medici.png',
walk: [[0, 360], [0, 336], [160, 290], [262, 240], [288, 212], [312, 208], [340, 222], [470, 300], [545, 360]],
depth: [[208, 0.32], [360, 1.25]],
@@ -364,7 +412,7 @@ export const story = {
// L'ingresso del campeggio: dalla Piazza a diritto; poco dopo, a destra, si sale al Bosco ai Frati.
campeggio: {
name: 'Ingresso del campeggio',
map: [16, 88],
map: [12, 84],
background: 'assets/scenes/campeggio.png',
walk: [[150, 360], [165, 262], [420, 266], [640, 286], [640, 360]],
depth: [[262, 0.6], [360, 1.15]],
@@ -395,7 +443,7 @@ export const story = {
// Il convento del Bosco ai Frati, nel bosco sopra il campeggio.
bosco_ai_frati: {
name: 'Bosco ai Frati',
map: [42, 88],
map: [12, 96],
background: 'assets/scenes/bosco-ai-frati.png',
walk: [[0, 304], [100, 298], [480, 292], [640, 300], [640, 360], [0, 360]],
depth: [[292, 0.78], [360, 1.1]],
@@ -431,7 +479,7 @@ export const story = {
// strada di fronte alla farmacia; da qui si scende ai giardini delle poste.
comune: {
name: 'Il Comune',
map: [6, 62],
map: [11, 45],
background: 'assets/scenes/comune-asilo.png',
walk: [[0, 360], [0, 262], [200, 256], [330, 250], [420, 268], [440, 305], [640, 330], [640, 360]],
depth: [[250, 0.5], [360, 1.15]],
@@ -464,14 +512,14 @@ export const story = {
id: 'ai_giardini', name: 'giù, verso i giardini', box: [596, 300, 44, 60], at: [620, 345], exit: { scene: 'giardini_poste', at: [580, 340], face: 'left' },
},
{
id: 'alla_farmacia', name: 'giù, verso la farmacia', box: [60, 334, 520, 26], at: [320, 354], exit: { scene: 'via_provinciale', at: [320, 345], face: 'up' },
id: 'alla_farmacia', name: 'giù, verso la farmacia', box: [60, 334, 520, 26], at: [320, 354], exit: { scene: 'via_provinciale', at: [622, 244], face: 'left' },
},
],
},
// I giardini delle poste: giù dal Comune; in fondo, le poste.
giardini_poste: {
name: 'Giardini delle poste',
map: [6, 78],
map: [11, 58],
background: 'assets/scenes/giardini-poste.png',
walk: [[0, 360], [0, 232], [640, 232], [640, 360]],
depth: [[232, 0.55], [360, 1.15]],
@@ -480,7 +528,7 @@ export const story = {
{
id: 'giochi', name: 'giochi', box: [196, 120, 330, 100], at: [360, 250], face: 'up',
actions: {
look: [{ say: 'Lo scivolo e le altalene. Sono troppo grande, ufficialmente. Ufficiosamente, un giro ci starebbe.' }],
look: [{ say: 'Lo scivolo e le altalene. Ho ventisette anni, ufficialmente. Ufficiosamente, un giro ci starebbe.' }],
use: [{ say: 'Un giro sull\'altalena! ... No, c\'è troppa gente che mi conosce.' }],
},
},
@@ -504,7 +552,7 @@ export const story = {
// Via Calimara: dalla Piazza scende alla farmacia, in Via Provinciale.
via_calimara: {
name: 'Via Calimara',
map: [26, 80],
map: [36, 58],
background: 'assets/scenes/via-calimara.png',
walk: [[0, 360], [0, 318], [330, 206], [400, 206], [560, 300], [600, 360]],
depth: [[206, 0.3], [360, 1.15]],
@@ -523,17 +571,17 @@ export const story = {
},
},
{
id: 'alla_provinciale', name: 'giù, verso la farmacia', box: [330, 176, 90, 40], at: [365, 210], exit: { scene: 'via_provinciale', at: [540, 345], face: 'up' },
id: 'alla_piazza', name: 'in fondo, la Piazza', box: [330, 176, 90, 40], at: [365, 210], exit: { scene: 'piazza', at: [360, 350], face: 'up' },
},
{
id: 'alla_piazza', name: 'su, verso la Piazza', box: [0, 330, 640, 30], at: [300, 354], exit: { scene: 'piazza', at: [360, 350], face: 'up' },
id: 'alla_provinciale', name: 'verso la farmacia', box: [0, 330, 640, 30], at: [300, 354], exit: { scene: 'via_provinciale', at: [600, 330], face: 'left' },
},
],
},
// Via Provinciale alla rotonda: il River e la farmacia. Andando avanti, la Pieve.
via_provinciale: {
name: 'Via Provinciale',
map: [36, 84],
map: [40, 71],
background: 'assets/scenes/via-provinciale.png',
walk: [[0, 360], [0, 312], [300, 302], [440, 262], [470, 238], [640, 238], [640, 360]],
depth: [[238, 0.45], [360, 1.15]],
@@ -554,26 +602,26 @@ export const story = {
},
},
{
id: 'area_feste', name: 'a sinistra, l\'area feste', box: [0, 250, 60, 110], at: [12, 330], exit: { scene: 'area_feste', at: [300, 350], face: 'up' },
id: 'al_ponte', name: 'a sinistra, verso il campo sportivo', box: [0, 230, 60, 130], at: [12, 320], exit: { scene: 'ponte_sieve', at: [300, 350], face: 'up' },
},
{
id: 'al_ponte', name: 'a diritto, verso il campo sportivo', box: [560, 222, 80, 46], at: [600, 248], exit: { scene: 'ponte_sieve', at: [300, 350], face: 'up' },
id: 'alla_pieve', name: 'dietro la farmacia, verso la Pieve', box: [470, 180, 120, 60], at: [560, 240], exit: { scene: 'pieve', at: [130, 345], face: 'right' },
},
{
id: 'alla_pieve', name: 'verso la Pieve', box: [0, 330, 213, 30], at: [100, 352], exit: { scene: 'pieve', at: [130, 345], face: 'right' },
id: 'area_feste', name: 'verso l\'area feste', box: [60, 330, 440, 30], at: [260, 352], exit: { scene: 'area_feste', at: [300, 350], face: 'up' },
},
{
id: 'al_comune', name: 'di fronte alla farmacia, verso il Comune', box: [213, 330, 214, 30], at: [320, 352], exit: { scene: 'comune', at: [320, 350], face: 'up' },
id: 'al_comune', name: 'verso il Comune', box: [592, 140, 48, 96], at: [622, 244], exit: { scene: 'comune', at: [320, 350], face: 'up' },
},
{
id: 'alla_calimara', name: 'Via Calimara, verso la Piazza', box: [427, 330, 213, 30], at: [540, 352], exit: { scene: 'via_calimara', at: [365, 210], face: 'down' },
id: 'alla_calimara', name: 'Via Calimara, verso la Piazza', box: [520, 260, 120, 100], at: [600, 330], exit: { scene: 'via_calimara', at: [300, 350], face: 'up' },
},
],
},
// L'area feste (il parco Antonio Berti): dalla rotonda del River, a sinistra.
area_feste: {
name: 'Area feste',
map: [40, 99],
map: [30, 84],
background: 'assets/scenes/area-feste.png',
walk: [[0, 360], [0, 250], [260, 190], [420, 190], [640, 240], [640, 360]],
depth: [[190, 0.35], [360, 1.15]],
@@ -593,14 +641,17 @@ export const story = {
},
},
{
id: 'alla_rotonda', name: 'indietro, verso la rotonda', box: [0, 330, 640, 30], at: [300, 354], exit: { scene: 'via_provinciale', at: [12, 330], face: 'right' },
id: 'alla_polisportiva', name: 'in fondo, verso il campo sportivo', box: [360, 168, 110, 34], at: [400, 198], exit: { scene: 'polisportiva', at: [320, 265], face: 'down' },
},
{
id: 'alla_rotonda', name: 'indietro, verso la rotonda', box: [0, 330, 640, 30], at: [300, 354], exit: { scene: 'via_provinciale', at: [260, 345], face: 'up' },
},
],
},
// Il ponte sulla Sieve, proseguendo la Provinciale dalla farmacia; di là dal ponte, la polisportiva.
ponte_sieve: {
name: 'Ponte sulla Sieve',
map: [30, 94],
map: [48, 84],
background: 'assets/scenes/ponte-sieve.png',
walk: [[0, 360], [0, 252], [180, 226], [300, 202], [342, 202], [380, 214], [330, 238], [330, 300], [460, 330], [640, 318], [640, 360]],
depth: [[202, 0.4], [360, 1.15]],
@@ -622,14 +673,14 @@ export const story = {
id: 'alla_polisportiva', name: 'di là dal ponte, il campo sportivo', box: [250, 180, 110, 36], at: [320, 206], exit: { scene: 'polisportiva_principale', at: [40, 330], face: 'right' },
},
{
id: 'alla_provinciale', name: 'indietro, verso la farmacia', box: [0, 330, 640, 30], at: [300, 354], exit: { scene: 'via_provinciale', at: [600, 248], face: 'left' },
id: 'alla_provinciale', name: 'indietro, verso la farmacia', box: [0, 330, 640, 30], at: [300, 354], exit: { scene: 'via_provinciale', at: [12, 320], face: 'right' },
},
],
},
// La polisportiva: passato il ponte, prima il campo principale con la tribuna; proseguendo il secondario, coi campi da padel e tennis.
polisportiva: {
name: 'Polisportiva',
map: [12, 99],
name: 'Campo secondario',
map: [62, 96],
background: 'assets/scenes/polisportiva-secondario.png',
walk: [[0, 360], [0, 330], [300, 262], [430, 222], [600, 210], [640, 212], [640, 360]],
depth: [[210, 0.4], [360, 1.15]],
@@ -648,12 +699,22 @@ export const story = {
},
},
{
id: 'padel', name: 'campi da padel e da tennis', box: [520, 190, 120, 40], at: [600, 214], face: 'right', default: 'walk',
id: 'tennis', name: 'campi da tennis', box: [520, 190, 120, 40], at: [600, 214], face: 'right', default: 'walk',
actions: {
walk: [{ say: 'Più avanti ci sono i campi da tennis e da padel.' }, { say: 'Il padel, nel 2007, non sapevo nemmeno cosa fosse. Lo scopriranno i miei genitori, tra qualche anno.' }],
look: [{ say: 'Laggiù i campi da tennis e da padel. Racchette, palline e gente che si lamenta del sole.' }],
walk: [{ say: 'Più avanti ci sono i campi da tennis. Racchette, palline e gente che si lamenta del sole.' }],
look: [{ say: 'Laggiù i campi da tennis.' }],
},
},
{
id: 'padel', name: 'capannone del padel', box: [0, 110, 90, 180], at: [40, 345], face: 'left',
actions: {
look: [{ say: 'Il capannone verde del padel.' }, { say: 'Il padel, nel 2007, non so nemmeno cosa sia. Tra qualche anno ci giocheranno tutti, me compreso.' }],
open: [{ say: 'Chiuso. E poi non saprei nemmeno da che parte si tiene la racchetta.' }],
},
},
{
id: 'all_area_feste', name: 'dietro il campo, verso l\'area feste', box: [150, 130, 190, 50], at: [320, 265], exit: { scene: 'area_feste', at: [400, 198], face: 'down' },
},
{
id: 'al_principale', name: 'indietro, verso il campo principale', box: [0, 330, 640, 30], at: [100, 354], exit: { scene: 'polisportiva_principale', at: [620, 330], face: 'left' },
},
@@ -661,7 +722,7 @@ export const story = {
},
polisportiva_principale: {
name: 'Campo principale',
map: [22, 99],
map: [40, 96],
background: 'assets/scenes/polisportiva-principale.png',
walk: [[0, 298], [640, 298], [640, 360], [0, 360]],
depth: [[298, 1.0], [360, 1.2]],
@@ -688,10 +749,67 @@ export const story = {
},
],
},
// Via Provinciale, a destra dalla Pieve: il forno; poi a sinistra la stazione, avanti «alla Luna» e Campomigliaio.
forno: {
name: 'Il forno',
map: [86, 58],
background: 'assets/scenes/forno-conti.png',
walk: [[0, 360], [0, 268], [640, 268], [640, 360]],
depth: [[268, 0.8], [360, 1.15]],
entry: [40, 330],
hotspots: [
{
id: 'forno', name: 'forno', box: [100, 40, 420, 220], at: [320, 290], face: 'up',
actions: {
look: [{ say: 'Il forno. Il profumo del pane arriva fino alla Pieve, e la domenica mattina fino a casa mia.' }],
open: [{ say: 'Una schiacciata calda... no, prima il palio. Però l\'odore me lo porto dietro.' }],
},
},
{
id: 'alla_stazione', name: 'a sinistra, la stazione', box: [0, 220, 40, 110], at: [16, 300], exit: { scene: 'stazione', at: [320, 340], face: 'up' },
},
{
id: 'alla_luna', name: 'avanti, verso «alla Luna» e Campomigliaio', box: [600, 230, 40, 130], at: [630, 330], face: 'right', default: 'walk',
actions: {
walk: [{ say: 'Più avanti c\'è «alla Luna», e poi Campomigliaio, il mio rione: i blu.' }, { say: 'Ci torno quando ho ritrovato il palio. A mani vuote non mi ci faccio vedere.' }],
look: [{ say: 'La Provinciale va avanti verso «alla Luna» e Campomigliaio.' }],
},
},
{
id: 'alla_pieve', name: 'indietro, verso la Pieve', box: [60, 334, 520, 26], at: [320, 354], exit: { scene: 'pieve', at: [588, 250], face: 'left' },
},
],
},
stazione: {
name: 'La stazione',
map: [88, 71],
background: 'assets/scenes/stazione.png',
walk: [[0, 360], [0, 270], [640, 270], [640, 360]],
depth: [[270, 0.75], [360, 1.15]],
entry: [320, 340],
hotspots: [
{
id: 'stazione', name: 'stazione', box: [200, 30, 440, 200], at: [400, 290], face: 'up',
actions: {
look: [{ say: 'La stazione della Faentina. Da qui i treni vanno a Firenze e a Faenza, con calma.' }, { say: 'Molta calma.' }],
},
},
{
id: 'bar', name: 'bar della stazione', box: [360, 196, 50, 66], at: [385, 290], face: 'up',
actions: {
look: [{ say: 'Il bar della stazione. Qui si aspetta il treno, e quando il treno è in ritardo si aspetta un altro caffè.' }],
open: [{ say: 'Non ho tempo per un caffè. E poi il caffè mi fa tremare come la carretta del Palio.' }],
},
},
{
id: 'al_forno', name: 'indietro, verso il forno', box: [0, 330, 640, 30], at: [320, 354], exit: { scene: 'forno', at: [16, 320], face: 'right' },
},
],
},
// Livello 1: Villa Adami, vista dalla salita della Fortezza guardando in discesa.
villa_adami: {
name: 'Villa Adami',
map: [34, 48],
map: [46, 32],
background: 'assets/scenes/villa-adami.png',
walk: [[0, 272], [30, 246], [60, 244], [110, 256], [190, 268], [360, 296], [440, 288], [520, 276], [560, 268], [612, 262], [614, 272], [520, 288], [500, 292], [500, 360], [0, 360]],
depth: [[244, 0.5], [360, 1.2]],
@@ -718,7 +836,7 @@ export const story = {
// Tra il livello 1 e il 2: la salita di Villa Adami, con la casa del leone. Si sale alla Fortezza.
salita_villa_adami: {
name: 'Salita di Villa Adami',
map: [30, 32],
map: [38, 19],
background: 'assets/scenes/salita-villa-adami.png',
walk: [[0, 318], [100, 312], [282, 318], [300, 300], [318, 262], [336, 252], [420, 266], [640, 296], [640, 360], [0, 360]],
depth: [[252, 0.5], [360, 1.1]],
@@ -736,7 +854,7 @@ export const story = {
{
id: 'verso_scuola', name: 'strada verso la scuola', box: [0, 286, 120, 44], at: [40, 336], face: 'left', exit: { scene: 'scuola', at: [300, 350], face: 'up' },
actions: {
look: [{ say: 'Di là si va alla scuola. Ci passo già abbastanza tempo durante l\'anno.' }],
look: [{ say: 'Di là si va alla scuola. Ci ho passato abbastanza anni, grazie.' }],
},
},
{
@@ -750,7 +868,7 @@ export const story = {
// La strada da Pieve a Cardetole: il posticino della Carza, il ponticino, l'area camper.
carza: {
name: 'Il posticino della Carza',
map: [54, 80],
map: [60, 58],
background: 'assets/scenes/carza.png',
walk: [[60, 360], [250, 262], [300, 218], [350, 218], [420, 262], [600, 360]],
depth: [[218, 0.4], [360, 1.15]],
@@ -779,7 +897,7 @@ export const story = {
},
ponticino: {
name: 'Il ponticino sulla Carza',
map: [62, 86],
map: [64, 71],
background: 'assets/scenes/ponticino-carza.png',
walk: [[250, 360], [438, 198], [478, 198], [560, 360]],
depth: [[198, 0.3], [360, 1.15]],
@@ -808,7 +926,7 @@ export const story = {
},
area_camper: {
name: 'Area camper',
map: [70, 92],
map: [70, 84],
background: 'assets/scenes/area-camper.png',
walk: [[0, 360], [0, 260], [200, 232], [380, 240], [450, 248], [640, 300], [640, 360]],
depth: [[232, 0.5], [360, 1.15]],
@@ -840,7 +958,7 @@ export const story = {
// Il prato del parco dei camper visto dall'altra parte: per i ragazzi, «il campo del Giannini».
campo_giannini: {
name: 'Il campo del Giannini',
map: [66, 98],
map: [82, 96],
background: 'assets/scenes/campo-giannini.png',
walk: [[0, 360], [0, 214], [300, 208], [460, 210], [640, 220], [640, 360]],
depth: [[208, 0.4], [360, 1.15]],
@@ -867,7 +985,7 @@ export const story = {
// Cardetole, il rione dei verdi, dove abita Andrea: giù dalla Pieve.
cardetole: {
name: 'Cardetole',
map: [78, 96],
map: [90, 84],
background: 'assets/scenes/cardetole.png',
walk: [[0, 360], [0, 344], [120, 332], [200, 304], [262, 292], [330, 292], [372, 296], [640, 266], [640, 360]],
depth: [[266, 0.55], [360, 1.15]],
@@ -885,7 +1003,7 @@ export const story = {
id: 'platano', name: 'platano', box: [90, 0, 170, 216], at: [200, 306], face: 'up',
actions: {
look: [{ say: 'Il prato sotto casa. Qui le porte le facevamo con le maglie per terra: due maglie, un palo ciascuna.' }, { say: 'E ogni gol era «Era fuori!», «No, era dentro!».' }],
use: [{ say: 'Arrampicarmi? Mia mamma mi vede dalla finestra.' }],
use: [{ say: 'Arrampicarmi? Alla mia età, e davanti a tutto il condominio?' }],
},
},
{
@@ -896,7 +1014,7 @@ export const story = {
// L'ingresso della scuola, giù per la strada dalla salita di Villa Adami: dal cancello alle porte a vetri.
scuola: {
name: 'La scuola',
map: [8, 32],
map: [14, 19],
background: 'assets/scenes/scuola.png',
walk: [[110, 360], [118, 226], [140, 222], [268, 220], [290, 232], [520, 360]],
depth: [[220, 0.42], [360, 1.32]],
@@ -905,22 +1023,22 @@ export const story = {
{
id: 'pino', name: 'pino', box: [222, 40, 120, 70], at: [250, 232], face: 'up',
actions: {
look: [{ say: 'Un pino a ombrello enorme. Alla ricreazione, tutti all\'ombra lì sotto.' }],
look: [{ say: 'Un pino a ombrello enorme. Alla ricreazione, tutti all\'ombra lì sotto. Sembra ieri.' }],
},
},
{
id: 'bandiere', name: 'bandiere', box: [110, 110, 170, 52], at: [200, 230], face: 'up',
actions: {
look: [{ say: 'Il tricolore e la bandiera europea. Almeno loro a scuola ci stanno volentieri.' }],
take: [{ say: 'Rubare una bandiera davanti alla scuola? Poi chi la sente la preside.' }],
take: [{ say: 'Rubare una bandiera davanti alla scuola? Ci manca solo che mi richiamino in presidenza, a ventisette anni.' }],
},
},
{
id: 'porte', name: 'porte della scuola', box: [130, 164, 136, 56], at: [200, 230], face: 'up',
actions: {
look: [{ say: 'Le porte a vetri della scuola. Di là ci sono i banchi, la lavagna e la campanella.' }],
open: [{ say: 'A scuola? A maggio? Nemmeno per sogno.' }],
walk: [{ say: 'A scuola? A maggio? Nemmeno per sogno.' }],
open: [{ say: 'Tornare a scuola? A ventisette anni? Nemmeno per sogno.' }],
walk: [{ say: 'Tornare a scuola? A ventisette anni? Nemmeno per sogno.' }],
},
},
{
@@ -937,7 +1055,7 @@ export const story = {
// Il viale dei cipressi, la strada bianca tra la Fortezza e il Trebbio: in fondo c'è il castello.
viale_cipressi: {
name: 'Viale dei cipressi',
map: [55, 15],
map: [60, 6],
background: 'assets/scenes/viale-cipressi.png',
walk: [[30, 360], [200, 300], [288, 252], [312, 250], [420, 300], [600, 360]],
depth: [[250, 0.16], [360, 1.2]],
@@ -960,7 +1078,7 @@ export const story = {
},
trebbio: {
name: 'Castello del Trebbio',
map: [80, 15],
map: [84, 6],
background: 'assets/scenes/trebbio.png',
music: 'assets/audio/ricordi.mp3',
walk: [[86, 308], [300, 306], [356, 308], [470, 312], [500, 324], [486, 360], [88, 360], [80, 330]],
@@ -981,7 +1099,7 @@ export const story = {
id: 'pergolato', name: 'pergolato', box: [278, 222, 122, 52], at: [328, 312], face: 'up',
actions: {
look: [{ say: 'Il pergolato, coi suoi pilastri. Un giorno li conto tutti.' }],
take: [{ say: 'Una vite? Ci vuole la vendemmia, non un ragazzo.' }],
take: [{ say: 'Una vite? Ci vuole la vendemmia, non uno con le mani in tasca.' }],
},
},
{