A ghost 👻 hides under one of three pumpkins 🎃. Watch where it goes, follow the pumpkins as they shuffle faster and faster, then pick the one hiding the ghost. Every correct guess scores a point and starts a harder round. One wrong pick and the game is over. How long can your eyes keep up?
.shuffle-game {
text-align: center;
}
.instructions {
max-width: 500px;
margin: 0 auto 15px;
font-size: 1em;
color: #555;
}
.shuffle-info {
margin-bottom: 15px;
font-size: 1.1em;
}
.shuffle-table {
position: relative;
width: 320px;
max-width: 100%;
height: 130px;
margin: 0 auto;
border: 3px solid #ff7518;
border-radius: 10px;
background: radial-gradient(circle at 50% 0%, #3b2a5a 0%, #1a1025 70%);
}
.cup {
position: absolute;
top: 25px;
width: 80px;
height: 80px;
cursor: pointer;
transition: left 0.3s ease-in-out;
-webkit-tap-highlight-color: transparent;
}
.cup-ghost,
.cup-top {
position: absolute;
left: 0;
width: 100%;
font-size: 3.2em;
line-height: 80px;
}
.cup-ghost {
top: 0;
visibility: hidden;
}
.cup-top {
top: 0;
transition: transform 0.3s;
}
.cup.lifted .cup-top {
transform: translateY(-45px);
}
.cup.lifted .cup-ghost {
visibility: visible;
}
.shuffle-message {
margin-top: 15px;
font-weight: bold;
}
.start-btn {
margin-top: 15px;
padding: 10px 20px;
font-size: 1em;
background-color: #ff7518;
color: #1a1025;
font-weight: bold;
border: none;
border-radius: 5px;
cursor: pointer;
}
.start-btn:hover {
background-color: #ff8f45;
}
.start-btn:disabled {
background-color: #ccc;
cursor: not-allowed;
}
<div class="shuffle-game">
<h1>🎃 Ghost Shuffle 👻</h1>
<div class="instructions">
A ghost hides under one of the pumpkins. Watch closely while they shuffle, then find the ghost! Each round gets faster.
</div>
<div class="shuffle-info">Round: <span id="shuffleRound">0</span> | Score: <span id="shuffleScore">0</span></div>
<div class="shuffle-table" id="shuffleTable">
<div class="cup" data-id="0"><span class="cup-ghost">👻</span><span class="cup-top">🎃</span></div>
<div class="cup" data-id="1"><span class="cup-ghost">👻</span><span class="cup-top">🎃</span></div>
<div class="cup" data-id="2"><span class="cup-ghost">👻</span><span class="cup-top">🎃</span></div>
</div>
<div class="shuffle-message" id="shuffleMessage">Press "Start" if you dare...</div>
<button class="start-btn" id="shuffleStart">Start</button>
</div>
const table = document.getElementById('shuffleTable');
const cups = Array.from(document.querySelectorAll('.cup'));
const roundDisplay = document.getElementById('shuffleRound');
const scoreDisplay = document.getElementById('shuffleScore');
const message = document.getElementById('shuffleMessage');
const startButton = document.getElementById('shuffleStart');
const hiddenScore = document.getElementById('hiddenScore');
const SLOT_WIDTH = 100;
let slots = [0, 1, 2]; // slots[position] = cup index
let ghostCup = 0;
let round = 0;
let score = 0;
let canPick = false;
let playing = false;
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
function layoutCups() {
const offset = (table.clientWidth - SLOT_WIDTH * 3) / 2 + (SLOT_WIDTH - 80) / 2;
slots.forEach((cupIndex, position) => {
cups[cupIndex].style.left = offset + position * SLOT_WIDTH + 'px';
});
}
function setLifted(cup, lifted) {
cup.classList.toggle('lifted', lifted);
}
async function shuffleCups(swaps, duration) {
cups.forEach(cup => cup.style.transitionDuration = duration + 'ms');
for (let i = 0; i < swaps; i++) {
const a = Math.floor(Math.random() * 3);
let b;
do {
b = Math.floor(Math.random() * 3);
} while (b === a);
[slots[a], slots[b]] = [slots[b], slots[a]];
layoutCups();
await wait(duration + 40);
}
}
async function playRound() {
round++;
roundDisplay.textContent = round;
canPick = false;
message.textContent = 'Watch the ghost...';
cups.forEach(cup => setLifted(cup, false));
cups.forEach(cup => cup.querySelector('.cup-ghost').style.visibility = '');
ghostCup = Math.floor(Math.random() * 3);
cups[ghostCup].classList.add('lifted');
await wait(1000);
setLifted(cups[ghostCup], false);
await wait(400);
message.textContent = 'Shuffling...';
await shuffleCups(4 + round * 2, Math.max(120, 450 - round * 40));
if (!playing) {
return;
}
message.textContent = 'Where is the ghost?';
canPick = true;
}
async function pick(cup, index) {
if (!canPick || !playing) {
return;
}
canPick = false;
setLifted(cup, true);
if (index === ghostCup) {
score++;
scoreDisplay.textContent = score;
hiddenScore.value = score; // Update hidden score field
message.textContent = 'Boo! You found it!';
await wait(1000);
if (playing) {
playRound();
}
} else {
playing = false;
setLifted(cups[ghostCup], true);
message.textContent = 'Wrong pumpkin! Final score: ' + score;
startButton.disabled = false;
document.querySelector('.share-buttons').style.display = 'flex'; // Show share buttons
}
}
function startGame() {
score = 0;
round = 0;
playing = true;
slots = [0, 1, 2];
scoreDisplay.textContent = score;
roundDisplay.textContent = round;
hiddenScore.value = score;
startButton.disabled = true;
document.querySelector('.share-buttons').style.display = 'none';
cups.forEach(cup => cup.style.transitionDuration = '0ms');
layoutCups();
playRound();
}
cups.forEach((cup, index) => cup.addEventListener('click', () => pick(cup, index)));
layoutCups();
window.addEventListener('resize', layoutCups);
startButton.addEventListener('click', startGame);