JSFiddle - React, Tailwind, and code Playground
HTML
<div id="candyGame">
<section id="startScreen" class="screen active start-screen">
<p class="eyebrow">WEEKLY SMALL TALKS · CANDY HOUSE</p>
<div class="hero-candy">🍬</div>
<h1>Candy Label Rescue</h1>
<p class="lead">The Cursed Piece has mixed up every label in the Candy House. Remember where each label belongs, then fix the chaos.</p>
<div class="how-to">
<span><b>1</b> Remember</span>
<span><b>2</b> Watch the shuffle</span>
<span><b>3</b> Choose YES or BUT…</span>
</div>
<button id="startBtn" class="main-btn">Enter the Candy House</button>
</section>
<section id="gameScreen" class="screen">
<header class="game-header">
<div>
<p class="eyebrow">CANDY LABEL RESCUE</p>
<h2 id="roundTitle">Level 1</h2>
</div>
<div class="score-box"><strong id="scoreText">0</strong><small>stars</small></div>
</header>
<div class="progress-track"><div id="progressFill"></div></div>
<div id="phaseMessage" class="phase-message" aria-live="polite"></div>
<div id="countdown" class="countdown"></div>
<div id="candyBoard" class="candy-board"></div>
<div id="decisionPanel" class="decision-panel hidden">
<p id="decisionQuestion"></p>
<div class="decision-buttons">
<button id="yesBtn" class="yes-btn">YES</button>
<button id="butBtn" class="but-btn">BUT…</button>
</div>
</div>
<div id="feedbackPanel" class="feedback-panel hidden">
<div id="feedbackIcon" class="feedback-icon"></div>
<h3 id="feedbackTitle"></h3>
<p id="feedbackText"></p>
<button id="nextBtn" class="main-btn">Next level</button>
</div>
</section>
<section id="machineScreen" class="screen machine-screen">
<p class="eyebrow">ALL THREE LEVELS COMPLETE</p>
<h2>Pull the Candy Machine Lever</h2>
<p class="lead">Pull the handle downward to print your final Candy House result.</p>
<div...
CSS
:root {
--ink: #35222d;
--cream: #fff3df;
--pink: #e75f92;
--plum: #6d336d;
--gold: #f0b64b;
--mint: #64ad9b;
--red: #bd3f59;
}
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
color: var(--ink);
background:
radial-gradient(circle at 15% 8%, rgba(255,255,255,.82), transparent 22%),
radial-gradient(circle at 85% 15%, rgba(231,95,146,.18), transparent 25%),
linear-gradient(145deg, #f9dfbc, #d9b5bc);
font-family: Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
}
button { font: inherit; }
#candyGame {
width: min(100%, 940px);
min-height: 100vh;
margin: auto;
padding: clamp(20px, 4vw, 44px);
}
.screen { display: none; animation: screenIn .35s ease; }
.screen.active { display: block; }
.hidden { display: none !important; }
@keyframes screenIn {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: none; }
}
.start-screen, .machine-screen, .result-screen { max-width: 720px; margin: auto; text-align: center; }
.eyebrow { margin: 0 0 10px; color: #83536b; font-size: 12px; font-weight: 950; letter-spacing: .14em; }
h1, h2, h3 { margin: 0; font-family: Georgia, "Times New Roman", serif; line-height: 1.05; }
h1 { font-size: clamp(42px, 8vw, 72px); }
h2 { font-size: clamp(32px, 5vw, 48px); }
h3 { font-size: 28px; }
.lead { max-width: 650px; margin: 16px auto 24px; font-size: clamp(16px, 2.4vw, 20px); line-height: 1.55; }
.hero-candy { margin: 6px 0 10px; font-size: 84px; filter: drop-shadow(0 12px 10px rgba(68,37,51,.18)); animation: candyFloat 1.5s ease-in-out infinite alternate; }
@keyframes candyFloat { to { transform: translateY(-8px) rotate(5deg); } }
.how-to { display: flex; justify-content: center; gap: 10px; flex-wrap: wrap; margin: 26px 0; }
.how-to span { padding: 10px 14px; border: 1px solid rgba(53,34,45,.15); border-radius: 999px; background: rgba(255,243,223,.72); font-size: 13px;...
JavaScript
function initCandyGame() {
const CANDIES = [
{ emoji: "💗", label: "Velvet Whisper", effect: "It tastes like berries… BUT it makes you speak only in rhymes for one minute." },
{ emoji: "🌙", label: "Fizz No. 7", effect: "It tastes fizzy… BUT it makes everything around you seem to move in slow motion." },
{ emoji: "🦇", label: "Lucky Loop", effect: "It tastes sour… BUT it makes your next little mistake feel surprisingly funny." },
{ emoji: "🎃", label: "Secret Snap", effect: "It tastes creamy… BUT it gives you one wonderfully impractical idea." },
{ emoji: "⭐", label: "Tiny Thunder", effect: "It tastes slightly salty… BUT it makes your footsteps sparkle for ten seconds." },
{ emoji: "🔮", label: "Glass Echo", effect: "It tastes like lemon… BUT it repeats the last funny sound it heard." }
];
const LABEL_COLOR = "#6d336d";
const ROUNDS = [
{ title: "Level 1 · First Mix-Up", candyIds: [0,1,2,3], shuffle: [1,0,3,2], target: 2, seconds: 3, answerSeconds: 7 },
{ title: "Level 2 · Candy Rush", candyIds: [0,1,2,3,4], shuffle: [4,2,1,3,0], target: 3, seconds: 3, answerSeconds: 7 },
{ title: "Level 3 · Total Candy Chaos", candyIds: [0,1,2,3,4,5], shuffle: [5,2,4,0,1,3], target: 4, seconds: 3, answerSeconds: 7 }
];
const $ = selector => document.querySelector(selector);
const screens = [...document.querySelectorAll(".screen")];
let roundIndex = 0;
let score = 0;
let phase = "idle";
let currentRound = null;
let displayedLabels = [];
let toastTimer = null;
let decisionTimer = null;
function showScreen(id) {
screens.forEach(screen => screen.classList.toggle("active", screen.id === id));
window.scrollTo({ top: 0, behavior: "smooth" });
}
function toast(message) {
const el = $("#toast");
el.textContent = message;
el.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(() => el.classList.remove("show"), 1900);
}
function...