fraction-factory / index.html
drbinna's picture
Update index.html
6bef773 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fraction Factory</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
background: #000000;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
padding: 20px;
}
.game-container {
background: white;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
padding: 30px;
max-width: 900px;
width: 100%;
}
.header {
text-align: center;
margin-bottom: 20px;
}
.header h1 {
color: #667eea;
font-size: 2.5em;
margin-bottom: 10px;
}
.header p {
color: #666;
font-size: 1.1em;
}
.stats {
display: flex;
justify-content: space-around;
margin-bottom: 20px;
padding: 15px;
background: #f0f0f0;
border-radius: 10px;
}
.stat {
text-align: center;
}
.stat-label {
font-size: 0.9em;
color: #666;
margin-bottom: 5px;
}
.stat-value {
font-size: 1.8em;
font-weight: bold;
color: #667eea;
}
.game-canvas {
width: 100%;
border: 3px solid #667eea;
border-radius: 10px;
background: #e8f4f8;
display: block;
}
.controls {
margin-top: 20px;
display: flex;
gap: 10px;
flex-wrap: wrap;
justify-content: center;
}
.answer-btn {
padding: 15px 30px;
font-size: 1.2em;
font-weight: bold;
border: 3px solid #667eea;
background: white;
color: #667eea;
border-radius: 10px;
cursor: pointer;
transition: all 0.3s;
min-width: 120px;
}
.answer-btn:hover {
background: #667eea;
color: white;
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.3);
}
.answer-btn:active {
transform: translateY(0);
}
.answer-btn.correct {
background: #4ade80;
border-color: #4ade80;
color: white;
}
.answer-btn.wrong {
background: #f87171;
border-color: #f87171;
color: white;
}
.start-screen, .game-over-screen {
text-align: center;
padding: 40px;
}
.start-btn, .restart-btn {
padding: 20px 50px;
font-size: 1.5em;
font-weight: bold;
background: #667eea;
color: white;
border: none;
border-radius: 15px;
cursor: pointer;
transition: all 0.3s;
margin-top: 20px;
}
.start-btn:hover, .restart-btn:hover {
background: #764ba2;
transform: scale(1.05);
}
.feedback {
text-align: center;
margin-top: 15px;
font-size: 1.2em;
font-weight: bold;
min-height: 30px;
}
.feedback.correct {
color: #4ade80;
}
.feedback.wrong {
color: #f87171;
}
.hidden {
display: none;
}
.instructions {
background: #fff3cd;
padding: 15px;
border-radius: 10px;
margin-bottom: 20px;
border: 2px solid #ffc107;
}
.instructions h3 {
color: #856404;
margin-bottom: 10px;
}
.instructions p {
color: #856404;
line-height: 1.6;
}
</style>
</head>
<body>
<div class="game-container">
<div class="header">
<h1>🏭 Fraction Factory</h1>
<p>Solve fraction problems before they fall off the conveyor belt!</p>
</div>
<div id="startScreen" class="start-screen">
<div class="instructions">
<h3>How to Play:</h3>
<p>📦 Fraction problems move across the conveyor belt<br>
⚡ Solve each problem in 5-10 seconds<br>
✅ Correct answers keep the boxes moving<br>
❌ Wrong answers make boxes fall off<br>
🎯 Get as many correct as you can!</p>
</div>
<button class="start-btn" onclick="startGame()">Start Factory</button>
</div>
<div id="gameScreen" class="hidden">
<div class="stats">
<div class="stat">
<div class="stat-label">Score</div>
<div class="stat-value" id="score">0</div>
</div>
<div class="stat">
<div class="stat-label">Streak</div>
<div class="stat-value" id="streak">0</div>
</div>
<div class="stat">
<div class="stat-label">Lives</div>
<div class="stat-value" id="lives">❤️❤️❤️</div>
</div>
</div>
<canvas id="gameCanvas" class="game-canvas" width="800" height="300"></canvas>
<div class="controls" id="controls">
<!-- Answer buttons will be added dynamically -->
</div>
<div class="feedback" id="feedback"></div>
</div>
<div id="gameOverScreen" class="game-over-screen hidden">
<h2 style="color: #667eea; font-size: 2.5em; margin-bottom: 20px;">Factory Closed!</h2>
<p style="font-size: 1.3em; margin-bottom: 10px;">Final Score: <span id="finalScore" style="color: #667eea; font-weight: bold;">0</span></p>
<p style="font-size: 1.3em; margin-bottom: 30px;">Correct Answers: <span id="correctCount" style="color: #4ade80; font-weight: bold;">0</span></p>
<button class="restart-btn" onclick="restartGame()">Play Again</button>
</div>
</div>
<script>
// Game state
let gameState = {
score: 0,
streak: 0,
lives: 3,
currentProblem: null,
boxPosition: 0,
isMoving: false,
correctAnswers: 0,
totalAnswers: 0
};
// JSON-driven problems (this would normally be loaded from a file)
const problems = [
{ question: "1/2 + 1/4", answer: "3/4", options: ["3/4", "1/4", "2/4", "3/6"] },
{ question: "2/3 + 1/3", answer: "1", options: ["1", "3/6", "2/3", "3/9"] },
{ question: "3/4 - 1/4", answer: "1/2", options: ["1/2", "2/4", "1/4", "2/8"] },
{ question: "1/2 × 1/2", answer: "1/4", options: ["1/4", "1/2", "2/4", "1/8"] },
{ question: "3/5 + 1/5", answer: "4/5", options: ["4/5", "4/10", "2/5", "3/10"] },
{ question: "5/6 - 2/6", answer: "1/2", options: ["1/2", "3/6", "1/3", "2/3"] },
{ question: "1/3 + 1/6", answer: "1/2", options: ["1/2", "2/9", "1/9", "2/6"] },
{ question: "2/5 × 5/2", answer: "1", options: ["1", "10/10", "4/10", "5/5"] },
{ question: "7/8 - 3/8", answer: "1/2", options: ["1/2", "4/8", "4/16", "1/4"] },
{ question: "1/4 + 2/4", answer: "3/4", options: ["3/4", "3/8", "1/2", "2/4"] }
];
let canvas, ctx;
let animationId;
function startGame() {
document.getElementById('startScreen').classList.add('hidden');
document.getElementById('gameScreen').classList.remove('hidden');
canvas = document.getElementById('gameCanvas');
ctx = canvas.getContext('2d');
gameState = {
score: 0,
streak: 0,
lives: 3,
currentProblem: null,
boxPosition: 0,
isMoving: false,
correctAnswers: 0,
totalAnswers: 0
};
updateStats();
loadNextProblem();
}
function loadNextProblem() {
// Pick a random problem
const problem = problems[Math.floor(Math.random() * problems.length)];
gameState.currentProblem = problem;
gameState.boxPosition = 0;
gameState.isMoving = true;
// Shuffle options
const shuffledOptions = [...problem.options].sort(() => Math.random() - 0.5);
// Create answer buttons
const controls = document.getElementById('controls');
controls.innerHTML = '';
shuffledOptions.forEach(option => {
const btn = document.createElement('button');
btn.className = 'answer-btn';
btn.textContent = option;
btn.onclick = () => checkAnswer(option, btn);
controls.appendChild(btn);
});
document.getElementById('feedback').textContent = '';
document.getElementById('feedback').className = 'feedback';
animate();
}
function animate() {
if (!gameState.isMoving) return;
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw conveyor belt
ctx.fillStyle = '#666';
ctx.fillRect(0, 220, canvas.width, 80);
// Draw conveyor belt lines
ctx.strokeStyle = '#fbbf24';
ctx.lineWidth = 2;
for (let i = 0; i < canvas.width; i += 40) {
ctx.beginPath();
ctx.moveTo(i + (gameState.boxPosition % 40), 260);
ctx.lineTo(i + 20 + (gameState.boxPosition % 40), 260);
ctx.stroke();
}
// Draw factory elements
ctx.fillStyle = '#8b5cf6';
ctx.fillRect(10, 100, 60, 120);
ctx.fillStyle = '#6d28d9';
ctx.fillRect(20, 110, 40, 40);
// Draw box with problem
const boxX = 100 + gameState.boxPosition;
const boxY = 150;
// Box shadow
ctx.fillStyle = 'rgba(0,0,0,0.2)';
ctx.fillRect(boxX + 5, boxY + 5, 120, 80);
// Box
ctx.fillStyle = '#fbbf24';
ctx.fillRect(boxX, boxY, 120, 80);
ctx.strokeStyle = '#f59e0b';
ctx.lineWidth = 3;
ctx.strokeRect(boxX, boxY, 120, 80);
// Problem text
ctx.fillStyle = '#1f2937';
ctx.font = 'bold 20px Arial';
ctx.textAlign = 'center';
ctx.fillText(gameState.currentProblem.question, boxX + 60, boxY + 45);
ctx.font = '16px Arial';
ctx.fillText('= ?', boxX + 60, boxY + 65);
// Move box
gameState.boxPosition += 1.5;
// Check if box fell off
if (gameState.boxPosition > canvas.width - 100) {
handleTimeout();
return;
}
animationId = requestAnimationFrame(animate);
}
function checkAnswer(selected, btn) {
if (!gameState.isMoving) return;
gameState.isMoving = false;
cancelAnimationFrame(animationId);
gameState.totalAnswers++;
const feedback = document.getElementById('feedback');
const allBtns = document.querySelectorAll('.answer-btn');
if (selected === gameState.currentProblem.answer) {
// Correct answer
gameState.score += 10 + (gameState.streak * 5);
gameState.streak++;
gameState.correctAnswers++;
btn.classList.add('correct');
feedback.textContent = '✓ Correct! Great job!';
feedback.className = 'feedback correct';
allBtns.forEach(b => b.disabled = true);
setTimeout(() => {
loadNextProblem();
}, 1500);
} else {
// Wrong answer
gameState.streak = 0;
gameState.lives--;
btn.classList.add('wrong');
feedback.textContent = `✗ Not quite! The answer was ${gameState.currentProblem.answer}`;
feedback.className = 'feedback wrong';
// Show correct answer
allBtns.forEach(b => {
if (b.textContent === gameState.currentProblem.answer) {
b.classList.add('correct');
}
b.disabled = true;
});
if (gameState.lives <= 0) {
setTimeout(gameOver, 2000);
} else {
setTimeout(() => {
loadNextProblem();
}, 2000);
}
}
updateStats();
}
function handleTimeout() {
gameState.isMoving = false;
gameState.streak = 0;
gameState.lives--;
gameState.totalAnswers++;
const feedback = document.getElementById('feedback');
feedback.textContent = '⏰ Time\'s up! The box fell off!';
feedback.className = 'feedback wrong';
const allBtns = document.querySelectorAll('.answer-btn');
allBtns.forEach(b => {
if (b.textContent === gameState.currentProblem.answer) {
b.classList.add('correct');
}
b.disabled = true;
});
updateStats();
if (gameState.lives <= 0) {
setTimeout(gameOver, 2000);
} else {
setTimeout(() => {
loadNextProblem();
}, 2000);
}
}
function updateStats() {
document.getElementById('score').textContent = gameState.score;
document.getElementById('streak').textContent = gameState.streak;
let hearts = '';
for (let i = 0; i < gameState.lives; i++) {
hearts += '❤️';
}
for (let i = gameState.lives; i < 3; i++) {
hearts += '🖤';
}
document.getElementById('lives').textContent = hearts;
}
function gameOver() {
document.getElementById('gameScreen').classList.add('hidden');
document.getElementById('gameOverScreen').classList.remove('hidden');
document.getElementById('finalScore').textContent = gameState.score;
document.getElementById('correctCount').textContent =
`${gameState.correctAnswers} out of ${gameState.totalAnswers}`;
}
function restartGame() {
document.getElementById('gameOverScreen').classList.add('hidden');
startGame();
}
</script>
</body>
</html>