Skip to content

Instantly share code, notes, and snippets.

@dabd
Last active June 24, 2025 22:23
Show Gist options
  • Select an option

  • Save dabd/bcbdf065e7360717492c3d761ec93aa9 to your computer and use it in GitHub Desktop.

Select an option

Save dabd/bcbdf065e7360717492c3d761ec93aa9 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Big Book of Words</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
user-select: none;
}
body {
font-family: 'Comic Sans MS', 'Arial Rounded MT Bold', Arial, sans-serif;
height: 100vh;
overflow: hidden;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
}
/* Animated background elements */
.bg-decoration {
position: absolute;
opacity: 0.1;
animation: float 20s infinite ease-in-out;
}
.star {
width: 30px;
height: 30px;
background: white;
clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
}
@keyframes float {
0%, 100% { transform: translateY(0) rotate(0deg); }
50% { transform: translateY(-20px) rotate(180deg); }
}
.main-container {
text-align: center;
width: 90%;
max-width: 400px;
padding: 20px;
}
h1 {
color: white;
font-size: 2.5em;
margin-bottom: 30px;
text-shadow: 3px 3px 6px rgba(0,0,0,0.3);
animation: bounce 2s infinite;
}
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
.button-container {
display: flex;
flex-direction: column;
gap: 20px;
margin-bottom: 30px;
}
.game-button {
background: #ff4444;
color: white;
border: none;
padding: 25px 40px;
font-size: 1.3em;
font-weight: bold;
border-radius: 50px;
cursor: pointer;
box-shadow: 0 8px 0 #cc0000, 0 10px 20px rgba(0,0,0,0.3);
transition: all 0.1s;
position: relative;
overflow: hidden;
}
.game-button:active {
transform: translateY(4px);
box-shadow: 0 4px 0 #cc0000, 0 5px 10px rgba(0,0,0,0.3);
}
.game-button:hover {
background: #ff5555;
}
/* Slot machine display */
.slot-machine {
display: none;
background: white;
border-radius: 20px;
padding: 30px;
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
margin-bottom: 20px;
}
.slot-display {
font-size: 4em;
font-weight: bold;
color: #333;
min-height: 100px;
display: flex;
align-items: center;
justify-content: center;
background: #f0f0f0;
border-radius: 15px;
padding: 20px;
margin: 20px 0;
position: relative;
overflow: hidden;
}
.slot-number {
animation: slotRoll 0.1s;
}
@keyframes slotRoll {
0% { transform: translateY(-100%); opacity: 0; }
100% { transform: translateY(0); opacity: 1; }
}
.rolling {
animation: roll 0.1s infinite;
}
@keyframes roll {
0% { transform: translateY(0); }
100% { transform: translateY(-20px); }
}
.back-button {
background: #4CAF50;
color: white;
border: none;
padding: 15px 30px;
font-size: 1.1em;
font-weight: bold;
border-radius: 30px;
cursor: pointer;
box-shadow: 0 5px 0 #388E3C, 0 7px 15px rgba(0,0,0,0.2);
transition: all 0.1s;
}
.back-button:active {
transform: translateY(3px);
box-shadow: 0 2px 0 #388E3C, 0 3px 8px rgba(0,0,0,0.2);
}
/* Image display for game mode 2 */
.image-display {
width: 200px;
height: 200px;
background: #f0f0f0;
border-radius: 15px;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto;
font-size: 3em;
}
.image-display img {
max-width: 100%;
max-height: 100%;
border-radius: 10px;
}
/* Confetti animation */
.confetti {
position: fixed;
width: 10px;
height: 10px;
background: #ff4444;
position: absolute;
animation: confettiFall 3s linear;
}
@keyframes confettiFall {
0% {
transform: translateY(-100vh) rotate(0deg);
opacity: 1;
}
100% {
transform: translateY(100vh) rotate(720deg);
opacity: 0;
}
}
/* Audio controls */
.sound-toggle {
position: absolute;
top: 20px;
right: 20px;
background: rgba(255,255,255,0.3);
border: none;
border-radius: 50%;
width: 50px;
height: 50px;
cursor: pointer;
font-size: 1.5em;
color: white;
transition: all 0.3s;
}
.sound-toggle:hover {
background: rgba(255,255,255,0.5);
transform: scale(1.1);
}
</style>
</head>
<body>
<!-- Background decorations -->
<div class="bg-decoration star" style="top: 10%; left: 10%;"></div>
<div class="bg-decoration star" style="top: 20%; right: 15%; animation-delay: -5s;"></div>
<div class="bg-decoration star" style="bottom: 30%; left: 20%; animation-delay: -10s;"></div>
<div class="bg-decoration star" style="bottom: 20%; right: 10%; animation-delay: -15s;"></div>
<!-- Sound toggle button -->
<button class="sound-toggle" onclick="toggleSound()">๐Ÿ”Š</button>
<!-- Main menu -->
<div id="mainMenu" class="main-container">
<h1>Big Book of Words</h1>
<div class="button-container">
<button class="game-button" onclick="startGame(1)">Find the Page</button>
<button class="game-button" onclick="startGame(2)">Find the Image</button>
</div>
</div>
<!-- Game display -->
<div id="gameDisplay" class="main-container" style="display: none;">
<div class="slot-machine">
<h2 id="gameTitle" style="color: #333; margin-bottom: 20px;"></h2>
<div id="slotDisplay" class="slot-display">
<span id="slotContent"></span>
</div>
</div>
<button class="back-button" onclick="backToMenu()">Back to Menu</button>
</div>
<script>
// Sound effects using Web Audio API
let audioContext;
let soundEnabled = true;
function initAudio() {
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
}
}
function playSound(type) {
if (!soundEnabled) return;
initAudio();
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
switch(type) {
case 'click':
oscillator.frequency.setValueAtTime(800, audioContext.currentTime);
oscillator.frequency.exponentialRampToValueAtTime(400, audioContext.currentTime + 0.1);
gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.1);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 0.1);
break;
case 'roll':
oscillator.frequency.setValueAtTime(200 + Math.random() * 200, audioContext.currentTime);
gainNode.gain.setValueAtTime(0.1, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.05);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 0.05);
break;
case 'win':
oscillator.frequency.setValueAtTime(523.25, audioContext.currentTime); // C5
oscillator.frequency.setValueAtTime(659.25, audioContext.currentTime + 0.1); // E5
oscillator.frequency.setValueAtTime(783.99, audioContext.currentTime + 0.2); // G5
gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.5);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 0.5);
break;
}
}
function toggleSound() {
soundEnabled = !soundEnabled;
document.querySelector('.sound-toggle').textContent = soundEnabled ? '๐Ÿ”Š' : '๐Ÿ”‡';
}
// Excluded pages (example set - you can modify this)
const excludedPages = new Set([100, 150, 200, 250, 300, 350, 400]);
// Sample images for demo (replace with actual images)
const sampleImages = [
'๐Ÿถ', '๐Ÿฑ', '๐Ÿญ', '๐Ÿน', '๐Ÿฐ', '๐ŸฆŠ', '๐Ÿป', '๐Ÿผ', '๐Ÿจ', '๐Ÿฏ',
'๐Ÿฆ', '๐Ÿฎ', '๐Ÿท', '๐Ÿธ', '๐Ÿต', '๐Ÿ”', '๐Ÿง', '๐Ÿฆ', '๐Ÿค', '๐Ÿฆ†',
'๐Ÿฆ…', '๐Ÿฆ‰', '๐Ÿฆ‡', '๐Ÿบ', '๐Ÿ—', '๐Ÿด', '๐Ÿฆ„', '๐Ÿ', '๐Ÿ›', '๐Ÿฆ‹',
'๐ŸŒ', '๐Ÿž', '๐Ÿœ', '๐ŸฆŸ', '๐Ÿฆ—', '๐Ÿฆ‚', '๐Ÿข', '๐Ÿ', '๐ŸฆŽ', '๐Ÿฆ–',
'๐Ÿฆ•', '๐Ÿ™', '๐Ÿฆ‘', '๐Ÿฆ', '๐Ÿฆž', '๐Ÿฆ€', '๐Ÿก', '๐Ÿ ', '๐ŸŸ', '๐Ÿฌ'
];
let currentGame = 0;
let isRolling = false;
function startGame(gameMode) {
playSound('click');
currentGame = gameMode;
document.getElementById('mainMenu').style.display = 'none';
document.getElementById('gameDisplay').style.display = 'block';
const gameTitle = gameMode === 1 ? 'Find the Page' : 'Find the Image';
document.getElementById('gameTitle').textContent = gameTitle;
// Reset display
document.getElementById('slotContent').textContent = '?';
document.querySelector('.slot-machine').style.display = 'block';
// Start rolling after a short delay
setTimeout(() => rollSlotMachine(), 300);
}
function rollSlotMachine() {
if (isRolling) return;
isRolling = true;
const slotContent = document.getElementById('slotContent');
const duration = 3000; // 3 seconds of rolling
const interval = 100; // Update every 100ms
let elapsed = 0;
const rollInterval = setInterval(() => {
elapsed += interval;
playSound('roll');
if (currentGame === 1) {
// Generate random page number
let randomPage;
do {
randomPage = Math.floor(Math.random() * (458 - 7 + 1)) + 7;
} while (excludedPages.has(randomPage));
slotContent.textContent = randomPage;
slotContent.className = 'slot-number';
} else {
// Show random image
const randomImage = sampleImages[Math.floor(Math.random() * sampleImages.length)];
slotContent.innerHTML = `<span style="font-size: 2em;">${randomImage}</span>`;
slotContent.className = 'slot-number';
}
// Slow down near the end
if (elapsed >= duration - 1000) {
clearInterval(rollInterval);
setTimeout(() => {
finalRoll();
}, 200);
}
}, interval);
}
function finalRoll() {
const slotContent = document.getElementById('slotContent');
let finalResult;
if (currentGame === 1) {
// Final page number
do {
finalResult = Math.floor(Math.random() * (458 - 7 + 1)) + 7;
} while (excludedPages.has(finalResult));
slotContent.textContent = finalResult;
} else {
// Final image
finalResult = sampleImages[Math.floor(Math.random() * sampleImages.length)];
slotContent.innerHTML = `<span style="font-size: 2em;">${finalResult}</span>`;
}
playSound('win');
createConfetti();
isRolling = false;
}
function createConfetti() {
const colors = ['#ff4444', '#44ff44', '#4444ff', '#ffff44', '#ff44ff', '#44ffff'];
for (let i = 0; i < 50; i++) {
setTimeout(() => {
const confetti = document.createElement('div');
confetti.className = 'confetti';
confetti.style.left = Math.random() * 100 + '%';
confetti.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
confetti.style.transform = `rotate(${Math.random() * 360}deg)`;
document.body.appendChild(confetti);
setTimeout(() => confetti.remove(), 3000);
}, i * 50);
}
}
function backToMenu() {
playSound('click');
document.getElementById('gameDisplay').style.display = 'none';
document.getElementById('mainMenu').style.display = 'block';
currentGame = 0;
}
// Handle orientation change
window.addEventListener('orientationchange', () => {
setTimeout(() => {
window.scrollTo(0, 0);
}, 500);
});
// Prevent zoom on double tap
let lastTouchEnd = 0;
document.addEventListener('touchend', (event) => {
const now = Date.now();
if (now - lastTouchEnd <= 300) {
event.preventDefault();
}
lastTouchEnd = now;
}, false);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment