diff --git a/assets/voices/andrea-2c7369689a.mp3 b/assets/voices/andrea-2c7369689a.mp3 deleted file mode 100644 index d5b7a64..0000000 Binary files a/assets/voices/andrea-2c7369689a.mp3 and /dev/null differ diff --git a/assets/voices/andrea-4266372068.mp3 b/assets/voices/andrea-4266372068.mp3 new file mode 100644 index 0000000..98f7e02 Binary files /dev/null and b/assets/voices/andrea-4266372068.mp3 differ diff --git a/assets/voices/andrea-9904de279c.mp3 b/assets/voices/andrea-9904de279c.mp3 deleted file mode 100644 index 15a7b5f..0000000 Binary files a/assets/voices/andrea-9904de279c.mp3 and /dev/null differ diff --git a/assets/voices/andrea-a372a71849.mp3 b/assets/voices/andrea-a372a71849.mp3 new file mode 100644 index 0000000..0807374 Binary files /dev/null and b/assets/voices/andrea-a372a71849.mp3 differ diff --git a/assets/voices/index.json b/assets/voices/index.json index 81e14e3..8849322 100644 --- a/assets/voices/index.json +++ b/assets/voices/index.json @@ -1984,8 +1984,8 @@ "sec": 2.79 }, "andrea|La fanfara degli alpini. Quando sfilavano per il paese suonando, s'affacciava tutto San Piero.": { - "file": "andrea-9904de279c.mp3", - "sec": 6.69 + "file": "andrea-a372a71849.mp3", + "sec": 6.3 }, "fanfara|Un'altra? Questa la sanno anche i sassi!": { "file": "fanfara-d1179f98fa.mp3", @@ -3676,8 +3676,8 @@ "sec": 5.94 }, "andrea|La Smarronata del 1993! Gli alpini, sotto il ponte: le bruciate, la polenta, il vino, la fanfara...": { - "file": "andrea-2c7369689a.mp3", - "sec": 10.99 + "file": "andrea-4266372068.mp3", + "sec": 10.39 }, "andrea|La macchina del tempo è sempre lì che aspetta.": { "file": "andrea-81cad76b69.mp3", diff --git a/src/engine/render.js b/src/engine/render.js index c83e58a..f61eb47 100644 --- a/src/engine/render.js +++ b/src/engine/render.js @@ -182,7 +182,6 @@ export function render(ctx, game, { hover, spots, debug, time = performance.now( : drawAndrea(ctx, s.x, s.y, game.scaleAt(s.y), s.facing, game.walking ? game.stride / 6 : null); // Durante il risveglio si guarda dagli occhi di Andrea: lui non si vede. const pov = game.closeup && game.story.closeups?.[game.closeup.id]?.type === 'risveglio'; - if (!pov) risveglioLayer(ctx, false); const queue = pov ? [] : [{ y: s.y, draw: drawAndreaNow }]; for (const p of game.people()) { const sheet = sprites.get(p.who); @@ -912,18 +911,6 @@ function drawDebug(ctx, game, { mouse, points = [], help }) { ctx.restore(); } -// La tela del risveglio (risveglio.js): una tela a parte sopra la scena, che c'è solo finché il risveglio dura. -function risveglioLayer(ctx, on = true) { - if (typeof document === 'undefined' || !ctx.canvas?.after) return null; - let layer = document.getElementById('risveglio'); - if (!on) { layer?.remove(); return null; } - if (!layer) { - layer = Object.assign(document.createElement('canvas'), { id: 'risveglio', width: WIDTH, height: HEIGHT }); - ctx.canvas.after(layer); - } - return layer.getContext('2d'); -} - // --- Il primo piano di un libro (story.closeups, game.closeup): la scena si oscura, le mani alzano il libro dal basso. // Le immagini hanno etichetta e pagine vuote: i testi si scrivono qui, nitidi. Una pagina sola gira, a fisarmonica // sulla piega; sotto c'è già l'ultima pagina. @@ -962,12 +949,7 @@ function drawCloseup(ctx, game, time) { // L'incantesimo va sopra la scena (con Andrea dentro), già disegnata. if (def.type === 'incanto') { drawIncanto(ctx, c); return; } // Il risveglio, visto da dentro gli occhi: anche lui sopra la scena già disegnata. - // Sul telefono (schermo touch) la versione leggera, senza filtri; sul computer quella con la sfocatura vera. - if (def.type === 'risveglio') { - const layer = risveglioLayer(ctx), light = matchMedia('(pointer: coarse)').matches; - if (layer) drawRisveglio(layer, c, backgrounds.get(game.backdrop()), { light }); - return; - } + if (def.type === 'risveglio') { drawRisveglio(ctx, c, backgrounds.get(game.backdrop())); return; } // Il telefonino del Barone: sale come il libro, e il sito nello schermo si allarga a tutta la scena. if (def.type === 'telefono') { const pic = src => { if (!backgrounds.has(src)) loadBackground(src); return backgrounds.get(src); }; diff --git a/src/engine/risveglio.js b/src/engine/risveglio.js index 72135b4..4e956b0 100644 --- a/src/engine/risveglio.js +++ b/src/engine/risveglio.js @@ -30,12 +30,12 @@ export function updateRisveglio(c, def, dt) { return { due, end: c.t >= END && c.fired >= lines.length }; } -// Il risveglio si disegna su una tela sua, appoggiata sopra la scena solo finché dura (render.js, `#risveglio`). -// Due versioni (Andrea, 31 ottobre): sul computer quella bella, con la sfocatura vera (ctx.filter); sul telefono -// (`light`) una leggera senza filtri, perché senza una scheda video la sfocatura a ogni fotogramma pesa: la nebbia è -// lo sfondo rimpicciolito e riallargato morbido, il bordo delle palpebre tante passate trasparenti. -const SMALL = [80, 45]; -let small = null, smallOf = null; +// Niente filtri e niente passate a tutto schermo (ctx.filter, il filter CSS e sedici palpebre trasparenti a ogni +// fotogramma lasciavano alla grafica un arretrato che si pagava dopo, a risveglio finito: il gioco si inceppava). +// La nebbia è lo sfondo rimpicciolito e riallargato morbido; le palpebre si disegnano nette su una tela piccola e +// si allargano di cinque volte con l'interpolazione, che sfuma il bordo da sé. Una versione sola, computer e telefono. +const SMALL = [80, 45], LIDS = [128, 72]; +let small = null, smallOf = null, lids = null; function blurred(bg) { if (smallOf !== bg) { small ??= Object.assign(document.createElement('canvas'), { width: SMALL[0], height: SMALL[1] }); @@ -47,23 +47,19 @@ function blurred(bg) { return small; } -export function drawRisveglio(ctx, c, bg, { light = false } = {}) { +export function drawRisveglio(ctx, c, bg) { const t = c.t, h = haze(t), open = openness(t), W = 640, H = 360; ctx.save(); - ctx.clearRect(0, 0, W, H); - // La scena annebbiata: lo sfondo sfocato sopra a quello nitido, più una seconda copia spostata che ondeggia (la - // vista doppia); tutto si dirada col passare del tempo. - if (h > 0.01 && bg) { - const sway = 14 * h, dx = Math.sin(c.age * 1.3) * sway, dy = Math.sin(c.age * 0.9 + 1) * sway * 0.35; - const fog = light ? blurred(bg) : bg; + // La scena annebbiata (lo sfondo sfocato sopra) e la vista doppia (una seconda copia, spostata, che ondeggia). + if (h > 0.01 && bg && typeof document !== 'undefined') { + const fog = blurred(bg), sway = 14 * h, dx = Math.sin(c.age * 1.3) * sway, dy = Math.sin(c.age * 0.9 + 1) * sway * 0.35; ctx.imageSmoothingEnabled = true; - if (!light) ctx.filter = `blur(${(5 * h).toFixed(2)}px)`; - ctx.globalAlpha = h; + ctx.globalAlpha = 0.85 * h; ctx.drawImage(fog, 0, 0, W, H); - ctx.globalAlpha = 0.45 * h; + ctx.globalAlpha = 0.4 * h; ctx.drawImage(fog, dx, dy, W, H); ctx.globalAlpha = 1; - ctx.filter = 'none'; + ctx.imageSmoothingEnabled = false; // La luce del mattino che abbaglia. ctx.fillStyle = `rgba(255,244,214,${0.22 * h})`; ctx.fillRect(0, 0, W, H); @@ -74,23 +70,22 @@ export function drawRisveglio(ctx, c, bg, { light = false } = {}) { v.addColorStop(1, `rgba(10,2,4,${0.85 * (1 - open * 0.75) * Math.max(h, 0.3)})`); ctx.fillStyle = v; ctx.fillRect(0, 0, W, H); - // Le palpebre: sopra e sotto, col bordo curvo e sfumato; chiuse, si vede il rosso scuro della luce che passa. - if (open < 0.999) { - const mid = H / 2, bulge = 70 + 60 * open, lid = (gap, sign) => { - const edge = mid + sign * gap, side = edge - sign * bulge, far = sign < 0 ? -20 : H + 20; - ctx.beginPath(); - ctx.moveTo(-20, far); ctx.lineTo(W + 20, far); ctx.lineTo(W + 20, side); - ctx.quadraticCurveTo(W / 2, edge * 2 - side, -20, side); - ctx.closePath(); ctx.fill(); - }; - if (light) { - // Il bordo morbido: passate trasparenti che sporgono verso l'occhio aperto, un pixel di più l'una. - ctx.fillStyle = 'rgba(22,4,6,0.11)'; - for (let i = 16; i > 0; i--) { lid(200 * open - i, -1); lid(200 * open - i, 1); } - } else ctx.filter = 'blur(6px)'; - ctx.fillStyle = 'rgb(22,4,6)'; - lid(200 * open, -1); lid(200 * open, 1); - ctx.filter = 'none'; + // Le palpebre: sopra e sotto, col bordo curvo; chiuse, si vede il rosso scuro della luce che passa. + if (open < 0.999 && typeof document !== 'undefined') { + lids ??= Object.assign(document.createElement('canvas'), { width: LIDS[0], height: LIDS[1] }); + const l = lids.getContext('2d'), k = LIDS[0] / W, mid = H / 2 * k, gap = 200 * open * k, bulge = (70 + 60 * open) * k; + l.clearRect(0, 0, ...LIDS); + l.fillStyle = 'rgb(22,4,6)'; + for (const sign of [-1, 1]) { + const edge = mid + sign * gap, side = edge - sign * bulge, far = sign < 0 ? -4 : LIDS[1] + 4; + l.beginPath(); + l.moveTo(-4, far); l.lineTo(LIDS[0] + 4, far); l.lineTo(LIDS[0] + 4, side); + l.quadraticCurveTo(LIDS[0] / 2, edge * 2 - side, -4, side); + l.closePath(); l.fill(); + } + ctx.imageSmoothingEnabled = true; + ctx.drawImage(lids, 0, 0, W, H); + ctx.imageSmoothingEnabled = false; } ctx.restore(); } diff --git a/style.css b/style.css index f06608d..037bd4c 100644 --- a/style.css +++ b/style.css @@ -82,8 +82,6 @@ body { display: flex; justify-content: center; overflow-x: hidden; -webkit-tap-h text-shadow: 2px 0 #000, -2px 0 #000, 0 2px #000, 0 -2px #000, 2px 2px #000, -2px -2px #000; } #speech:empty { display: none; } #speech { z-index: 3; } -/* La tela del risveglio, sopra la scena solo finché dura (render.js). */ -#risveglio { position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; z-index: 1; } /* Il Muro del Sanpierino sul telefonino del Barone: la pagina vera (assets/muro) larga 1067 pixel come la home del sito, rimpicciolita sulla scena da main.js (--muro-scale). */ #muro { position: absolute; left: 0; top: 0; width: 1067px; height: 600px; border: 0; z-index: 1; background: #f7e1c0; diff --git a/tests/risveglio.browser.mjs b/tests/risveglio.browser.mjs index e696c6d..180b22f 100644 --- a/tests/risveglio.browser.mjs +++ b/tests/risveglio.browser.mjs @@ -28,7 +28,6 @@ try { } await page.waitForFunction(() => !game.closeup && game.state.flags.intro, null, { timeout: 15000 }); await page.screenshot({ path: `${out}/${tag}-5-vecchietti.png` }); - assert.equal(await page.locator('#risveglio').count(), 0, 'finito il risveglio, la sua tela se ne va'); } assert.deepEqual(errors, []); console.log(`ok: schermate in ${out}`); diff --git a/tools/pronuncia.json b/tools/pronuncia.json index 8e45eab..6243e53 100644 --- a/tools/pronuncia.json +++ b/tools/pronuncia.json @@ -21,6 +21,5 @@ "Libici": "Lìbici", "mancano": "màncano", "console": "consòl", - "Mahhh... è l'INGORGOOOO!!!": "Maaaa, è l'Ingorgo! L'Ingorgooo!", - "fanfara": "fanfàra" + "Mahhh... è l'INGORGOOOO!!!": "Maaaa, è l'Ingorgo! L'Ingorgooo!" }