new ragebait 3 col

This commit is contained in:
2026-07-02 14:09:36 +02:00
parent bb3da28c9d
commit 5e63574f2d
2 changed files with 64 additions and 56 deletions

100
app.js
View File

@@ -346,8 +346,46 @@
).finished;
}
// rullo che atterra dritto sulla target
async function reelLand(el, finalY, duration) {
// Atterraggio di un rullo sulla target. Se teaseMs > 0 fa il RAGEBAIT:
// si ferma su una stanza adiacente sbagliata, tiene la suspense (teaseMs),
// poi scatta sulla vera. Funziona su QUALSIASI colonna.
async function reelLand(el, targetIndex, finalY, duration, teaseMs) {
// eventuale bluff: scegli una stanza adiacente diversa dalla vera
if (teaseMs > 0) {
const targetRoom = roomAtIndex(el, targetIndex);
let dir = Math.random() < 0.5 ? -1 : 1;
if (roomAtIndex(el, targetIndex + dir)?.id === targetRoom.id) dir = -dir;
if (roomAtIndex(el, targetIndex + dir)?.id === targetRoom.id) teaseMs = 0; // no adiacente
if (teaseMs > 0) {
const fakeRoom = roomAtIndex(el, targetIndex + dir);
const fakeY = -(targetIndex + dir - 1) * ITEM_H;
const col = el.parentElement;
// decelera e "si ferma" sulla stanza SBAGLIATA
await el.animate(
[{ transform: "translateY(0)" }, { transform: `translateY(${fakeY}px)` }],
{ duration, easing: "cubic-bezier(0.08, 0.85, 0.14, 1)", fill: "forwards" }
).finished;
Audio.reelStop();
// suspense su quella colonna
Audio.blip(330, 0.13, "sine", 0.14);
col.classList.add("teasing");
mc(`${fakeRoom.nome}...? 🤨`);
await sleep(teaseMs);
// SCATTO alla stanza vera
Audio.blip(200, 0.12, "sawtooth", 0.2, 90); // whoosh
await el.animate(
[{ transform: `translateY(${fakeY}px)` }, { transform: `translateY(${finalY}px)` }],
{ duration: 480, easing: "cubic-bezier(0.34, 1.56, 0.64, 1)", fill: "forwards" }
).finished;
col.classList.remove("teasing");
Audio.reelStop();
return;
}
}
// atterraggio diretto + micro-assestamento
await el.animate(
[{ transform: "translateY(0)" }, { transform: `translateY(${finalY}px)` }],
{ duration, easing: "cubic-bezier(0.12, 0.85, 0.18, 1)", fill: "forwards" }
@@ -356,42 +394,10 @@
Audio.reelStop();
}
// rullo con RAGEBAIT: si ferma sulla stanza sbagliata, suspense, poi scatta
async function reelLandTease(el, targetIndex, finalY) {
const targetRoom = roomAtIndex(el, targetIndex);
let dir = Math.random() < 0.5 ? -1 : 1;
if (roomAtIndex(el, targetIndex + dir)?.id === targetRoom.id) dir = -dir;
if (roomAtIndex(el, targetIndex + dir)?.id === targetRoom.id)
return reelLand(el, finalY, 4200); // niente adiacente valida
const fakeRoom = roomAtIndex(el, targetIndex + dir);
const fakeY = -(targetIndex + dir - 1) * ITEM_H;
// FASE 1: decelera e "si ferma" sulla stanza SBAGLIATA
await el.animate(
[{ transform: "translateY(0)" }, { transform: `translateY(${fakeY}px)` }],
{ duration: 3600, easing: "cubic-bezier(0.08, 0.85, 0.14, 1)", fill: "forwards" }
).finished;
Audio.reelStop();
// FASE 2: gaslighting — sembra fatta
Audio.blip(320, 0.18, "sine", 0.16);
const win = $(".reel-window");
win.classList.add("teasing");
mc(`Ferma su ${fakeRoom.nome}...? 🤨`);
await sleep(750);
// FASE 3: SCATTO alla stanza vera
Audio.blip(200, 0.14, "sawtooth", 0.22, 90); // whoosh
await el.animate(
[{ transform: `translateY(${fakeY}px)` }, { transform: `translateY(${finalY}px)` }],
{ duration: 520, easing: "cubic-bezier(0.34, 1.56, 0.64, 1)", fill: "forwards" }
).finished;
win.classList.remove("teasing");
Audio.reelStop();
}
// GIRO: i 3 rulli partono insieme e si fermano da sinistra a destra,
// allineandosi tutti sulla stanza assegnata (l'ultimo può fare il ragebait).
// allineandosi sulla stanza assegnata. OGNI colonna può fare il ragebait
// (in modo indipendente); le colonne più a destra tengono la suspense più a
// lungo, così il dramma "cascata" verso l'ultimo rullo.
async function spinReel(targetId) {
const targetIndex = reelEls.map((el) => buildStripIn(el, targetId))[0]; // uguale per tutti
const finalY = -(targetIndex - 1) * ITEM_H;
@@ -403,7 +409,7 @@
const mainDur = 4200;
setTimeout(zoomMachineSteady, mainDur / 2);
const stopRiser = Audio.riser(5.0);
const stopRiser = Audio.riser(5.6);
// tick sincronizzati sul 3° rullo (gira più a lungo)
let ticking = true;
@@ -418,16 +424,14 @@
requestAnimationFrame(loop);
})();
const wantTease = Math.random() < TEASE_CHANCE;
// stop staggerato sinistra -> destra
await Promise.all([
reelLand(reelEls[0], finalY, 2600),
reelLand(reelEls[1], finalY, 3300),
wantTease
? reelLandTease(reelEls[2], targetIndex, finalY)
: reelLand(reelEls[2], finalY, 4200),
]);
const durs = [2600, 3300, 4200];
await Promise.all(
reelEls.map((el, i) => {
// ogni colonna ha una sua chance di bluff; suspense crescente verso destra
const teaseMs = Math.random() < TEASE_CHANCE ? 380 + i * 260 : 0;
return reelLand(el, targetIndex, finalY, durs[i], teaseMs);
})
);
ticking = false;
stopRiser();