math-prodigy / index.html
busyhe's picture
Update index.html
f523b49 verified
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数学小天才</title>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'sans-serif'],
},
animation: {
'float': 'float 3s ease-in-out infinite',
'pulse-slow': 'pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite',
'fade-in': 'fadeIn 0.3s ease-out',
'fade-out': 'fadeOut 0.3s ease-out',
'slide-up': 'slideUp 0.8s cubic-bezier(0.34, 1.56, 0.64, 1)',
},
keyframes: {
float: {
'0%, 100%': { transform: 'translateY(0)' },
'50%': { transform: 'translateY(-10px)' },
},
fadeIn: {
'0%': { opacity: '0', transform: 'translateY(10px)' },
'100%': { opacity: '1', transform: 'translateY(0)' },
},
fadeOut: {
'0%': { opacity: '1', transform: 'translateY(0)' },
'100%': { opacity: '0', transform: 'translateY(-10px)' },
},
slideUp: {
'0%': { transform: 'translateY(100%)', opacity: '0' },
'100%': { transform: 'translateY(0)', opacity: '1' },
},
}
}
}
}
</script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<style>
@keyframes confetti-fall {
0% { transform: translateY(-100px) rotate(0deg); opacity: 1; }
100% { transform: translateY(100vh) rotate(360deg); opacity: 0; }
}
.animate-confetti {
animation: confetti-fall 2s linear forwards;
}
.linear-card {
background: rgba(255, 255, 255, 0.6);
backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 8px 32px rgba(31, 38, 135, 0.05);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.linear-card:hover {
box-shadow: 0 8px 32px rgba(31, 38, 135, 0.1);
transform: translateY(-2px);
}
.btn-transition {
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
.btn-scale:hover {
transform: scale(1.02);
}
.btn-scale:active {
transform: scale(0.98);
}
.elevate-on-hover {
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.elevate-on-hover:hover {
transform: translateY(-4px);
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1);
}
.slide-in {
animation: slideIn 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
@keyframes slideIn {
from { transform: translateY(20px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
.fade-in {
animation: fadeIn 0.3s ease-out forwards;
}
.bounce-animation {
animation: bounce 0.5s alternate infinite ease-in-out;
}
@keyframes bounce {
from { transform: translateY(-5px); }
to { transform: translateY(5px); }
}
/* Celebration animation */
.celebration-item {
position: absolute;
opacity: 0;
z-index: 100;
}
@keyframes celebrationRise {
0% {
transform: translateY(100vh) scale(0);
opacity: 1;
}
40% {
transform: translateY(60vh) scale(1);
opacity: 0.8;
}
80% {
opacity: 0.5;
}
100% {
transform: translateY(-100px) scale(0.5);
opacity: 0;
}
}
/* Mobile game mode styles */
.game-mode .game-header,
.game-mode .game-footer {
display: none;
}
.game-mode .game-wrapper {
margin-top: 0;
padding-top: 0.5rem;
}
.game-mode .answer-options {
grid-template-columns: 1fr !important;
gap: 0.5rem !important;
}
.game-mode .answer-btn {
padding: 0.75rem !important;
font-size: 1rem !important;
}
.game-mode .visual-aid {
gap: 0.25rem !important;
}
.game-mode .visual-item {
width: 1.75rem !important;
height: 1.75rem !important;
font-size: 0.75rem !important;
}
.game-mode #question {
font-size: 2rem !important;
margin-bottom: 0.5rem !important;
}
.game-mode .character {
font-size: 3rem !important;
}
.game-mode .stats-bar {
padding: 0.5rem !important;
margin-bottom: 0.5rem !important;
}
.game-mode .stats-item {
font-size: 0.875rem !important;
}
</style>
</head>
<body class="bg-gradient-to-br from-gray-50 to-gray-100 min-h-screen font-sans text-gray-800">
<div id="app" class="container mx-auto px-4 py-4 max-w-4xl relative">
<!-- Header (hidden during gameplay) -->
<header class="game-header text-center mb-6 fade-in">
<div class="w-16 h-16 mx-auto mb-4 linear-card rounded-full flex items-center justify-center shadow-sm hover:shadow-md transition-all elevate-on-hover">
<i class="fas fa-calculator text-2xl text-indigo-500"></i>
</div>
<h1 class="text-2xl font-bold text-gray-800 mb-2 tracking-tight">数学小天才</h1>
<p class="text-xs text-gray-500">快乐学习 · 轻松进步</p>
</header>
<!-- Main wrapper -->
<main class="game-wrapper">
<!-- Game selection screen -->
<div id="game-selection" class="p-4 linear-card rounded-xl overflow-hidden slide-in">
<h2 class="text-xl font-semibold text-center text-gray-700 mb-4">选择游戏模式</h2>
<div class="grid grid-cols-1 gap-3 mb-6">
<button onclick="startGame('addition')" class="linear-card btn-transition btn-scale py-3 px-4 rounded-lg hover:bg-indigo-50/50 text-indigo-600 font-medium flex items-center justify-center gap-2 border border-indigo-100">
<i class="fas fa-plus text-lg"></i>
<span>加法练习</span>
</button>
<button onclick="startGame('subtraction')" class="linear-card btn-transition btn-scale py-3 px-4 rounded-lg hover:bg-purple-50/50 text-purple-600 font-medium flex items-center justify-center gap-2 border border-purple-100">
<i class="fas fa-minus text-lg"></i>
<span>减法练习</span>
</button>
</div>
<div class="space-y-2">
<h3 class="text-base font-medium text-gray-700">难度设置</h3>
<div class="grid grid-cols-3 gap-2">
<label>
<input type="radio" name="difficulty" value="easy" checked class="hidden peer">
<div class="h-full linear-card peer-checked:bg-indigo-50/50 peer-checked:border-indigo-200 peer-checked:text-indigo-600 border border-gray-100 rounded-lg p-2 text-center cursor-pointer transition-all flex flex-col items-center">
<i class="fas fa-smile text-lg mb-1"></i>
<span class="text-xs">简单模式</span>
<span class="text-[0.6rem] text-gray-500 mt-0.5">数字1-5</span>
</div>
</label>
<label>
<input type="radio" name="difficulty" value="medium" class="hidden peer">
<div class="h-full linear-card peer-checked:bg-purple-50/50 peer-checked:border-purple-200 peer-checked:text-purple-600 border border-gray-100 rounded-lg p-2 text-center cursor-pointer transition-all flex flex-col items-center">
<i class="fas fa-meh text-lg mb-1"></i>
<span class="text-xs">中等模式</span>
<span class="text-[0.6rem] text-gray-500 mt-0.5">数字1-10</span>
</div>
</label>
<label>
<input type="radio" name="difficulty" value="hard" class="hidden peer">
<div class="h-full linear-card peer-checked:bg-rose-50/50 peer-checked:border-rose-200 peer-checked:text-rose-600 border border-gray-100 rounded-lg p-2 text-center cursor-pointer transition-all flex flex-col items-center">
<i class="fas fa-frown text-lg mb-1"></i>
<span class="text-xs">困难模式</span>
<span class="text-[0.6rem] text-gray-500 mt-0.5">数字1-20</span>
</div>
</label>
</div>
</div>
</div>
<!-- Game area -->
<div id="game-area" class="hidden">
<div class="flex justify-between items-center mb-3 linear-card bg-gradient-to-r from-indigo-50/50 to-purple-50/50 p-2 rounded-lg border border-gray-100 stats-bar">
<div class="flex items-center gap-1 stats-item">
<i class="fas fa-star text-amber-400 text-sm"></i>
<span>得分: <span id="score" class="font-medium text-indigo-600">0</span></span>
</div>
<div class="flex items-center gap-1 stats-item">
<i class="fas fa-clock text-purple-500 text-sm"></i>
<span>时间: <span id="time" class="font-medium text-purple-600">60</span></span>
</div>
<button onclick="backToMenu()" class="text-xs bg-white/70 px-2 py-0.5 rounded-full border border-gray-200 text-gray-600 hover:bg-white">
<i class="fas fa-times"></i>
</button>
</div>
<!-- Question card -->
<div class="linear-card rounded-lg p-3 mb-3">
<div id="question" class="text-2xl font-bold text-center mb-2"></div>
<div id="visual-aid" class="visual-aid flex justify-center items-center flex-wrap gap-1 mb-2"></div>
</div>
<!-- Answer options -->
<div id="answer-options" class="answer-options grid grid-cols-2 gap-2 mb-3"></div>
<!-- Feedback area -->
<div class="linear-card rounded-lg p-3 overflow-hidden">
<div id="feedback" class="text-center text-xs mb-2"></div>
<div id="character" class="character text-4xl text-center bounce-animation">🤔</div>
</div>
<!-- Next button -->
<div id="next-btn-container" class="hidden mt-3">
<button id="next-btn" onclick="nextQuestion()"
class="w-full py-2 answer-btn linear-card bg-gradient-to-r from-indigo-500 to-purple-500 text-white rounded-lg font-medium btn-transition btn-scale hover:from-indigo-600 hover:to-purple-600 hover:shadow-md">
下一题 <i class="fas fa-arrow-right ml-1"></i>
</button>
</div>
</div>
<!-- Results screen -->
<div id="results-screen" class="hidden">
<div class="linear-card rounded-xl p-4 text-center slide-up">
<div class="w-16 h-16 mx-auto mb-4 bg-gradient-to-r from-indigo-500 to-purple-500 text-white rounded-full flex items-center justify-center text-2xl shadow-sm">
🎓
</div>
<h2 class="text-xl font-bold mb-2">游戏完成!</h2>
<p class="text-gray-600 mb-3 text-xs">你的精彩表现值得赞赏</p>
<div class="linear-card rounded-lg p-4 inline-block mb-4 bg-gradient-to-r from-indigo-50/50 to-purple-50/50">
<p class="text-gray-600 mb-1 text-xs">最终得分</p>
<p id="final-score" class="text-3xl font-bold bg-gradient-to-r from-indigo-600 to-purple-600 bg-clip-text text-transparent">0</p>
</div>
<div class="flex flex-col gap-2">
<button onclick="restartGame()"
class="linear-card btn-transition btn-scale py-2 px-3 bg-indigo-500 hover:bg-indigo-600 text-white rounded-lg text-xs font-medium flex items-center justify-center gap-1">
<i class="fas fa-redo text-xs"></i> 再玩一次
</button>
<button onclick="backToMenu()"
class="linear-card btn-transition btn-scale py-2 px-3 bg-white hover:bg-gray-50 text-gray-700 border border-gray-200 rounded-lg text-xs font-medium flex items-center justify-center gap-1">
<i class="fas fa-home text-xs"></i> 返回菜单
</button>
</div>
</div>
</div>
</main>
<footer class="game-footer text-center mt-6 text-gray-500 text-xs">
<p><i class="fas fa-heart text-rose-400"></i> 为孩子打造 · © 2025 数学小天才</p>
</footer>
</div>
<script>
// Game variables
let currentGameType = '';
let currentDifficulty = 'easy';
let score = 0;
let timeLeft = 60;
let timer;
let currentQuestion = {};
let correctAnswer;
// DOM elements
const appElement = document.getElementById('app');
const gameSelection = document.getElementById('game-selection');
const gameArea = document.getElementById('game-area');
const resultsScreen = document.getElementById('results-screen');
const questionElement = document.getElementById('question');
const visualAidElement = document.getElementById('visual-aid');
const answerOptionsElement = document.getElementById('answer-options');
const feedbackElement = document.getElementById('feedback');
const characterElement = document.getElementById('character');
const scoreElement = document.getElementById('score');
const timeElement = document.getElementById('time');
const finalScoreElement = document.getElementById('final-score');
const nextButtonContainer = document.getElementById('next-btn-container');
const nextButton = document.getElementById('next-btn');
// Start game
function startGame(gameType) {
currentGameType = gameType;
const selectedDifficulty = document.querySelector('input[name="difficulty"]:checked');
currentDifficulty = selectedDifficulty ? selectedDifficulty.value : 'easy';
score = 0;
timeLeft = 60;
// Enter game mode (hide header/footer)
appElement.classList.add('game-mode');
gameSelection.classList.add('hidden');
gameArea.classList.remove('hidden');
updateScore();
updateTimer();
startTimer();
generateQuestion();
}
// Timer functions
function startTimer() {
clearInterval(timer);
timer = setInterval(() => {
timeLeft--;
updateTimer();
if (timeLeft <= 0) {
endGame();
}
}, 1000);
}
function updateTimer() {
timeElement.textContent = timeLeft;
// Change color when time is running out
if (timeLeft <= 10) {
timeElement.classList.remove('text-purple-600');
timeElement.classList.add('text-rose-500');
} else {
timeElement.classList.remove('text-rose-500');
timeElement.classList.add('text-purple-600');
}
}
// Generate question
function generateQuestion() {
nextButtonContainer.classList.add('hidden');
feedbackElement.textContent = '';
feedbackElement.className = 'text-center text-xs mb-2';
characterElement.textContent = '🤔';
characterElement.classList.add('bounce-animation');
characterElement.style.animation = '';
let num1, num2, maxNumber;
// Set max number based on difficulty
switch(currentDifficulty) {
case 'easy':
maxNumber = 5;
break;
case 'medium':
maxNumber = 10;
break;
case 'hard':
maxNumber = 20;
break;
}
if (currentGameType === 'addition') {
num1 = Math.floor(Math.random() * maxNumber) + 1;
num2 = Math.floor(Math.random() * maxNumber) + 1;
correctAnswer = num1 + num2;
questionElement.textContent = `${num1} + ${num2} = ?`;
// Create visual aid for addition
visualAidElement.innerHTML = '';
for (let i = 0; i < num1; i++) {
visualAidElement.innerHTML += `<div class="visual-item w-6 h-6 bg-gradient-to-br from-blue-400 to-blue-500 rounded-md flex items-center justify-center text-white font-bold text-xs shadow-sm">🍎</div>`;
}
visualAidElement.innerHTML += `<div class="text-lg font-bold mx-1 text-gray-500">+</div>`;
for (let i = 0; i < num2; i++) {
visualAidElement.innerHTML += `<div class="visual-item w-6 h-6 bg-gradient-to-br from-red-400 to-red-500 rounded-md flex items-center justify-center text-white font-bold text-xs shadow-sm">🍐</div>`;
}
} else { // Subtraction
num1 = Math.floor(Math.random() * maxNumber) + 1;
num2 = Math.floor(Math.random() * num1) + 1;
correctAnswer = num1 - num2;
questionElement.textContent = `${num1} - ${num2} = ?`;
// Create visual aid for subtraction
visualAidElement.innerHTML = '';
for (let i = 0; i < num1; i++) {
visualAidElement.innerHTML += `<div class="visual-item w-6 h-6 bg-gradient-to-br from-green-400 to-green-500 rounded-md flex items-center justify-center text-white font-bold text-xs shadow-sm">🐶</div>`;
}
visualAidElement.innerHTML += `<div class="text-lg font-bold mx-1 text-gray-500">-</div>`;
for (let i = 0; i < num2; i++) {
visualAidElement.innerHTML += `<div class="visual-item w-6 h-6 bg-gradient-to-br from-yellow-400 to-yellow-500 rounded-md flex items-center justify-center text-white font-bold text-xs shadow-sm">🏠</div>`;
}
}
// Generate answer options
generateAnswerOptions(correctAnswer, maxNumber);
}
function generateAnswerOptions(correct, max) {
answerOptionsElement.innerHTML = '';
let options = [correct];
// Generate 3 incorrect answers
while (options.length < 4) {
let wrongAnswer;
if (currentGameType === 'addition') {
wrongAnswer = Math.floor(Math.random() * (max * 2)) + 1;
} else {
wrongAnswer = Math.floor(Math.random() * max) + 1;
}
if (wrongAnswer !== correct && !options.includes(wrongAnswer)) {
options.push(wrongAnswer);
}
}
// Shuffle options
options = shuffleArray(options);
// Create buttons for each option
options.forEach(option => {
const button = document.createElement('button');
button.className = 'answer-btn linear-card btn-transition py-2 rounded-lg hover:bg-gray-50/50 border border-gray-100 text-sm font-medium';
button.textContent = option;
button.onclick = () => checkAnswer(option);
answerOptionsElement.appendChild(button);
});
}
// Check answer
function checkAnswer(selectedAnswer) {
// Disable all answer buttons
const buttons = answerOptionsElement.querySelectorAll('button');
buttons.forEach(button => {
button.disabled = true;
button.classList.remove('hover:bg-gray-50/50');
if (parseInt(button.textContent) === correctAnswer) {
button.classList.add('bg-green-50/50', 'border-green-200', 'text-green-600');
} else if (parseInt(button.textContent) === selectedAnswer && selectedAnswer !== correctAnswer) {
button.classList.add('bg-rose-50/50', 'border-rose-200', 'text-rose-600');
} else {
button.classList.add('opacity-70');
}
});
if (selectedAnswer === correctAnswer) {
// Correct answer
score += 10;
updateScore();
feedbackElement.textContent = '✓ 太棒了!答案正确';
feedbackElement.classList.add('text-green-500');
characterElement.textContent = '🎉';
characterElement.classList.remove('bounce-animation');
characterElement.style.animation = 'none';
void characterElement.offsetWidth; // Trigger reflow
characterElement.style.animation = 'bounce 0.5s alternate infinite ease-in-out';
createRisingCelebration();
buttons.forEach(button => {
if (parseInt(button.textContent) === correctAnswer) {
button.classList.add('animate-pulse');
setTimeout(() => button.classList.remove('animate-pulse'), 1500);
}
});
} else {
// Wrong answer
feedbackElement.textContent = `✕ 正确答案是 ${correctAnswer}`;
feedbackElement.classList.add('text-rose-500');
characterElement.textContent = '😢';
characterElement.style.animation = 'bounce 0.2s reverse 2';
}
nextButtonContainer.classList.remove('hidden');
}
// Create celebration effects (bottom-up animation)
function createRisingCelebration() {
const emojis = ['🎉', '✨', '🌟', '🎈', '🥳', '👍', '👏'];
const colors = ['#3B82F6', '#10B981', '#F59E0B', '#EF4444', '#8B5CF6', '#EC4899'];
for (let i = 0; i < 15; i++) {
setTimeout(() => {
const element = document.createElement('div');
element.className = 'celebration-item text-2xl';
element.textContent = emojis[Math.floor(Math.random() * emojis.length)];
// Random left position
const randomLeft = 5 + Math.random() * 90;
element.style.left = `${randomLeft}%`;
// Random delay and duration
const randomDelay = Math.random() * 0.5;
const randomDuration = 1 + Math.random() * 1;
// Random color
const randomColor = colors[Math.floor(Math.random() * colors.length)];
element.style.color = randomColor;
element.style.animation = `celebrationRise ${randomDuration}s ${randomDelay}s forwards`;
document.body.appendChild(element);
// Remove element after animation
setTimeout(() => {
element.remove();
}, (randomDelay + randomDuration) * 1000);
}, Math.random() * 300);
}
}
// Next question
function nextQuestion() {
generateQuestion();
}
// End game
function endGame() {
clearInterval(timer);
gameArea.classList.add('hidden');
resultsScreen.classList.remove('hidden');
finalScoreElement.textContent = score;
}
// Restart game
function restartGame() {
resultsScreen.classList.add('hidden');
startGame(currentGameType);
}
// Back to menu
function backToMenu() {
appElement.classList.remove('game-mode');
resultsScreen.classList.add('hidden');
gameArea.classList.add('hidden');
gameSelection.classList.remove('hidden');
}
// Update score
function updateScore() {
scoreElement.textContent = score;
}
// Utility functions
function shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - <a href="https://enzostvs-deepsite.hf.space?remix=busyhe/math-prodigy" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body>
</html>