суббота, 6 июня 2026 г.
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>Кот Басик: to be — 20 вопросов, 15 рыбок</title>
<style>
* {
box-sizing: border-box;
user-select: none;
}
body {
background: linear-gradient(145deg, #f9e7b3 0%, #f5cda0 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-family: 'Segoe UI', 'Comic Neue', 'Poppins', system-ui, sans-serif;
margin: 0;
padding: 16px;
}
.game-container {
width: 100%;
display: none;
}
/* Модальное окно */
.fullscreen-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.85);
backdrop-filter: blur(5px);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.modal-content {
background: #fffef0;
border-radius: 56px;
padding: 32px 28px;
max-width: 500px;
width: 85%;
text-align: center;
box-shadow: 0 20px 35px rgba(0,0,0,0.4), 0 0 0 8px #ffefc0, 0 0 0 12px #d9a13b;
}
.modal-content h1 {
font-size: 2.2rem;
font-weight: 900;
color: #aa5e1b;
margin: 0 0 10px 0;
}
.modal-content h2 {
font-size: 1.5rem;
font-weight: bold;
color: #6b3e0c;
margin: 10px 0;
}
.modal-content .to-be-red {
font-size: 3.2rem;
font-weight: 900;
color: #e53935;
margin: 15px 0;
letter-spacing: 2px;
}
.modal-content button {
background: #43a047;
border: none;
color: white;
font-weight: bold;
font-size: 1.3rem;
padding: 10px 24px;
border-radius: 50px;
cursor: pointer;
box-shadow: 0 5px 0 #2e6b31;
font-family: inherit;
margin-top: 20px;
}
.modal-content button:active {
transform: translateY(3px);
box-shadow: 0 2px 0 #2e6b31;
}
@media (max-width: 500px) {
.modal-content h1 { font-size: 1.6rem; }
.modal-content h2 { font-size: 1.2rem; }
.modal-content .to-be-red { font-size: 2.2rem; }
}
/* Основная игра */
.training-card {
max-width: 600px;
width: 100%;
background: #fffef7;
border-radius: 56px;
box-shadow: 0 20px 35px rgba(0,0,0,0.15), 0 0 0 6px #ffefc0, 0 0 0 10px #d9a13b;
overflow: hidden;
position: relative;
margin: 0 auto;
}
.fish-stack {
position: absolute;
top: 16px;
left: 20px;
background: rgba(255,255,210,0.9);
padding: 6px 10px;
border-radius: 24px;
display: flex;
flex-direction: column;
align-items: center;
gap: 2px;
z-index: 10;
min-width: 60px;
}
.fish-icon { font-size: 1.3rem; }
.fish-caught {
background: #6b3e0c;
padding: 2px 8px;
border-radius: 30px;
color: #ffde9c;
font-size: 1.1rem;
font-weight: bold;
}
.fish-total {
font-size: 0.85rem;
color: #8b5a2b;
background: rgba(255,255,200,0.8);
padding: 2px 6px;
border-radius: 20px;
}
.big-counter {
position: absolute;
top: 16px;
right: 20px;
font-size: 2.5rem;
font-weight: 900;
color: #e53935;
background: rgba(255,255,230,0.9);
padding: 4px 12px;
border-radius: 60px;
font-family: monospace;
line-height: 1;
z-index: 10;
}
.cat-header {
background: linear-gradient(135deg, #ff9f3d, #ffb347);
padding: 12px 12px 20px;
text-align: center;
border-bottom: 4px solid #e07c1f;
}
.cat-avatar {
font-size: 3.8rem;
cursor: pointer;
display: inline-block;
}
.cat-speech {
background: white;
border-radius: 40px;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 8px 16px;
margin-top: 6px;
font-weight: bold;
box-shadow: 0 3px 0 #e0a45e;
width: 260px;
max-width: 80vw;
height: 70px;
text-align: center;
word-break: break-word;
line-height: 1.35;
overflow-y: auto;
font-size: 0.95rem;
transition: color 0.1s ease;
}
.question-container {
padding: 12px 20px 8px;
text-align: center;
}
.translation-block {
background: #ffe5b4;
margin: 5px 0 12px;
padding: 10px 16px;
border-radius: 48px;
font-size: 1.2rem;
font-weight: bold;
color: #4a2a0e;
display: inline-block;
max-width: 95%;
}
.question-text {
font-size: 1.7rem;
font-weight: 800;
background: #fff0d6;
padding: 16px 12px;
border-radius: 48px;
color: #4d2e12;
min-height: 150px;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
line-height: 1.4;
}
.blank {
display: inline-block;
min-width: 80px;
background: #ffde9c;
border-radius: 50px;
padding: 0 12px;
margin: 0 4px;
font-weight: 900;
color: #b45f1b;
}
.blank.correct-highlight {
background: #a5d6a5;
color: #1e4a1e;
box-shadow: 0 0 0 2px #2e7d32;
}
.blank.wrong-highlight {
background: #ef9a9a;
color: #8b0000;
box-shadow: 0 0 0 2px #c62828;
}
.options {
display: flex;
justify-content: center;
gap: 14px;
margin: 16px 0 8px;
flex-wrap: wrap;
}
.verb-btn {
font-size: 1.8rem;
font-weight: bold;
padding: 8px 24px;
border: none;
background: #f7e05e;
color: #5a3a1a;
border-radius: 70px;
cursor: pointer;
box-shadow: 0 5px 0 #b97f2e;
font-family: inherit;
width: 100px;
}
.verb-btn:active { transform: translateY(3px); box-shadow: 0 2px 0 #b97f2e; }
.verb-btn:disabled { opacity: 0.6; cursor: not-allowed; transform: none; }
.next-button {
background: #43a047;
border: none;
color: white;
font-weight: bold;
font-size: 1.2rem;
padding: 8px 28px;
margin: 6px auto 16px;
border-radius: 50px;
cursor: pointer;
box-shadow: 0 4px 0 #2e6b31;
display: block;
width: fit-content;
}
.next-button:active:not(:disabled) { transform: translateY(2px); box-shadow: 0 1px 0 #2e6b31; }
.next-button:disabled {
background: #b0b0b0;
box-shadow: 0 4px 0 #6e6e6e;
cursor: not-allowed;
opacity: 0.7;
}
.reset-btn {
background: #c28641;
border: none;
color: white;
font-weight: bold;
padding: 8px 20px;
margin-bottom: 18px;
border-radius: 40px;
cursor: pointer;
box-shadow: 0 3px 0 #6b3e1a;
display: block;
width: fit-content;
margin: 0 auto 18px;
font-size: 0.9rem;
}
.reset-btn:active { transform: translateY(2px); box-shadow: 0 1px 0 #6b3e1a; }
@media (max-width: 480px) {
.big-counter { font-size: 1.8rem; top: 8px; right: 10px; }
.fish-stack { top: 8px; left: 10px; }
.verb-btn { font-size: 1.5rem; padding: 6px 16px; width: 85px; }
.question-text { font-size: 1.3rem; min-height: 140px; }
}
</style>
</head>
<body>
<div class="game-container" id="gameContainer">
<div class="training-card">
<div class="fish-stack">
<div class="fish-icon">🐟</div>
<div class="fish-caught" id="scoreDisplay">0</div>
<div class="fish-total">/15</div>
</div>
<div class="big-counter" id="bigLeftCounter">20</div>
<div class="cat-header">
<div class="cat-avatar" id="catAvatar">🐈⬛🐾</div>
<div class="cat-speech" id="catSpeech">Выбери am, is, are</div>
</div>
<div class="question-container">
<div class="translation-block" id="translationText">Я студент.</div>
<div class="question-text" id="questionText">I ___ a student.</div>
</div>
<div class="options">
<button class="verb-btn" data-verb="am">am</button>
<button class="verb-btn" data-verb="is">is</button>
<button class="verb-btn" data-verb="are">are</button>
</div>
<button class="next-button" id="nextBtn" disabled>➡ Дальше</button>
<button class="reset-btn" id="resetGameBtn">🔄 Сначала</button>
</div>
</div>
<script>
// 20 вопросов
const questionsList = [
{ text: "I ___ a beginner.", answer: "am", translation: "Я новичок." },
{ text: "She ___ my teacher.", answer: "is", translation: "Она моя учительница." },
{ text: "He ___ from France.", answer: "is", translation: "Он из Франции." },
{ text: "It ___ a cute cat.", answer: "is", translation: "Это милый кот." },
{ text: "We ___ happy.", answer: "are", translation: "Мы счастливы." },
{ text: "They ___ in the park.", answer: "are", translation: "Они в парке." },
{ text: "You ___ my friend.", answer: "are", translation: "Ты мой друг." },
{ text: "The children ___ at school.", answer: "are", translation: "Дети в школе." },
{ text: "The cat ___ sleeping.", answer: "is", translation: "Кот спит." },
{ text: "I ___ not ready.", answer: "am", translation: "Я не готов." },
{ text: "My parents ___ doctors.", answer: "are", translation: "Мои родители врачи." },
{ text: "This book ___ interesting.", answer: "is", translation: "Эта книга интересная." },
{ text: "We ___ good friends.", answer: "are", translation: "Мы хорошие друзья." },
{ text: "The weather ___ nice.", answer: "is", translation: "Погода отличная." },
{ text: "You ___ so kind.", answer: "are", translation: "Ты такой добрый." },
{ text: "I ___ hungry.", answer: "am", translation: "Я голоден." },
{ text: "The flowers ___ beautiful.", answer: "are", translation: "Цветы красивые." },
{ text: "He ___ at home now.", answer: "is", translation: "Он сейчас дома." },
{ text: "We ___ ready.", answer: "are", translation: "Мы готовы." },
{ text: "It ___ my birthday.", answer: "is", translation: "Это мой день рождения." }
];
const TOTAL_QS = 20;
const TARGET_FISH = 15;
// 15 комплиментов (базовые)
const compliments = [
"✨ Ты умница, София! ✨", "💫 Ты справляешься отлично! 💫", "🌸 Твоя смекалка — сила! 🌸",
"🎀 Ты настоящий боец! 🎀", "🌟 У тебя талант! 🌟", "🍭 София, ты супер! 🍭",
"🧸 Твоё упорство побеждает! 🧸", "🌼 Каждый раз всё лучше! 🌼", "⭐ Ты — звезда! ⭐",
"💖 Твоя голова светится! 💖", "🎉 Ты рождена для побед! 🎉", "🐱 Кот в восторге! 🐱",
"🌈 Ты делаешь успехи! 🌈", "🏆 София, ты лучшая! 🏆", "🍀 Легко и красиво! 🍀"
];
function randomCompliment() { return compliments[Math.floor(Math.random() * compliments.length)]; }
// Массив ярких цветов для комплиментов (и любых не-приветственных фраз)
const colorPalette = [
"#e91e63", "#9c27b0", "#673ab7", "#3f51b5", "#2196f3", "#00bcd4", "#009688", "#4caf50",
"#8bc34a", "#cddc39", "#ffeb3b", "#ffc107", "#ff9800", "#ff5722", "#795548", "#607d8b",
"#d81b60", "#f06292", "#ba68c8", "#64b5f6", "#4db6ac", "#81c784", "#ffb74d", "#a1887f"
];
function getRandomColor() {
return colorPalette[Math.floor(Math.random() * colorPalette.length)];
}
// Звуки
let audioCtx = null, soundOn = false;
function initAudio() { if (!audioCtx) try { audioCtx = new (window.AudioContext||window.webkitAudioContext)(); soundOn=true; } catch(e){} }
function playTone(freq, dur, vol=0.2, delay=0) {
if (!soundOn || !audioCtx) return;
const now = audioCtx.currentTime;
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.connect(gain);
gain.connect(audioCtx.destination);
osc.frequency.value = freq;
gain.gain.value = 0;
osc.start(now+delay);
gain.gain.linearRampToValueAtTime(vol, now+delay+0.01);
gain.gain.exponentialRampToValueAtTime(0.0001, now+delay+dur);
osc.stop(now+delay+dur);
}
function playCorrect() { playTone(880, 0.2, 0.2); }
function playWrong() { playTone(440, 0.3, 0.2); }
function playStart() { playTone(523.25, 0.12, 0.2); setTimeout(()=>playTone(659.25,0.12,0.2),130); setTimeout(()=>playTone(783.99,0.2,0.25),270); }
function playWin() { playTone(523.25,0.15,0.25); setTimeout(()=>playTone(659.25,0.15,0.25),180); setTimeout(()=>playTone(783.99,0.3,0.3),350); }
function playLose() { playTone(440,0.2,0.2); setTimeout(()=>playTone(392,0.2,0.2),250); setTimeout(()=>playTone(349.23,0.3,0.2),480); }
function enableAudio() { if (audioCtx && audioCtx.state==='suspended') audioCtx.resume(); else if(!audioCtx) initAudio(); }
document.body.addEventListener('click', ()=>enableAudio(), {once:true});
document.body.addEventListener('touchstart', ()=>enableAudio(), {once:true});
let currentQuestions = [], idx = 0, correct = 0, finished = false, waitNext = false, answered = false;
const questionEl = document.getElementById('questionText');
const translationEl = document.getElementById('translationText');
const scoreSpan = document.getElementById('scoreDisplay');
const bigCounter = document.getElementById('bigLeftCounter');
const nextBtn = document.getElementById('nextBtn');
const catSpeech = document.getElementById('catSpeech');
const catAvatar = document.getElementById('catAvatar');
const resetBtn = document.getElementById('resetGameBtn');
const btns = document.querySelectorAll('.verb-btn');
function shuffle(arr) { for (let i=arr.length-1; i>0; i--) { const j=Math.floor(Math.random()*(i+1)); [arr[i],arr[j]]=[arr[j],arr[i]]; } return arr; }
// Универсальная установка текста с возможностью случайного цвета (кроме greeting)
function setCatSpeech(text, isGreeting = false) {
catSpeech.innerHTML = text;
if (isGreeting) {
catSpeech.style.color = "#e53935"; // красный для приветствия
catSpeech.style.fontSize = "1.1rem";
} else {
catSpeech.style.color = getRandomColor();
catSpeech.style.fontSize = "0.95rem";
}
}
function updateUI() {
scoreSpan.innerText = correct;
bigCounter.innerText = TOTAL_QS - (idx+1);
}
function renderWithVerb(verb, hl) {
let txt = currentQuestions[idx].text;
if(txt.includes('___')) {
let cls = 'blank';
if(hl==='correct') cls+=' correct-highlight';
else if(hl==='wrong') cls+=' wrong-highlight';
questionEl.innerHTML = txt.replace('___', `<span class="${cls}">${verb}</span>`);
} else questionEl.innerText = txt;
translationEl.innerText = currentQuestions[idx].translation;
}
function renderEmpty() {
let txt = currentQuestions[idx].text;
if(txt.includes('___')) {
let parts = txt.split('___');
questionEl.innerHTML = `${parts[0]}<span class="blank">______</span>${parts[1]}`;
} else questionEl.innerText = txt;
translationEl.innerText = currentQuestions[idx].translation;
}
function blockBtns(block) { btns.forEach(b => { b.disabled = block; }); }
function setWait() { waitNext=true; answered=true; blockBtns(true); nextBtn.disabled=false; }
function finishWin() { finished=true; waitNext=false; answered=true; nextBtn.disabled=true; nextBtn.style.display='none'; blockBtns(true); setCatSpeech('София выиграла! 🎉', false); catAvatar.innerHTML='🐈🏆✨'; questionEl.innerHTML='🏆 ПОБЕДА! 🏆<br>Ты поймала 15 рыбок!'; translationEl.innerHTML='Отлично!'; bigCounter.innerText='0'; playWin(); }
function finishLose() { finished=true; waitNext=false; answered=true; nextBtn.disabled=true; nextBtn.style.display='none'; blockBtns(true); setCatSpeech('София. Ты лох.', false); catAvatar.innerHTML='🐈💔'; questionEl.innerHTML='😿 ПОРАЖЕНИЕ 😿<br>Не хватило рыбок...'; translationEl.innerHTML='Попробуй ещё!'; bigCounter.innerText='0'; playLose(); }
function handleAnswer(verb) {
if(finished || waitNext || answered) return;
const cur = currentQuestions[idx];
const ok = (verb === cur.answer);
if(ok) {
renderWithVerb(verb, 'correct');
correct++;
updateUI();
playCorrect();
catAvatar.innerHTML='🐈✨😸';
setCatSpeech('Мурр! Правильно! 👍', false);
if(correct >= TARGET_FISH) { finishWin(); return; }
} else {
renderWithVerb(cur.answer, 'wrong');
playWrong();
catAvatar.innerHTML='😿🐾';
setCatSpeech(`Правильно: "${cur.answer}"`, false);
}
setWait();
}
function nextQuestion() {
if(!waitNext || finished) return;
nextBtn.disabled = true;
if(idx+1 < TOTAL_QS) {
idx++;
waitNext=false; answered=false;
renderEmpty();
blockBtns(false);
setCatSpeech(randomCompliment(), false);
catAvatar.innerHTML='🐈⬛🐾';
updateUI();
} else {
if(correct >= TARGET_FISH) finishWin();
else finishLose();
}
}
function resetGame() {
currentQuestions = shuffle([...questionsList]);
idx=0; correct=0; finished=false; waitNext=false; answered=false;
nextBtn.disabled=true; nextBtn.style.display='block';
renderEmpty();
blockBtns(false);
setCatSpeech('София, слови 15 рыбок!', true);
catAvatar.innerHTML='🐈⬛🐾';
updateUI();
if(audioCtx && audioCtx.state==='suspended') audioCtx.resume();
playStart();
}
btns.forEach(btn => btn.addEventListener('click', () => { if(!finished && !waitNext && !answered) handleAnswer(btn.dataset.verb); }));
nextBtn.addEventListener('click', nextQuestion);
resetBtn.addEventListener('click', resetGame);
catAvatar.addEventListener('click', () => { if(!finished && !waitNext) setCatSpeech(randomCompliment(), false); });
// Стартовое окно
function showStart() {
const modal = document.createElement('div');
modal.className = 'fullscreen-modal';
modal.innerHTML = `
<div class="modal-content">
<h1>📘 Учебник Софии</h1>
<h2>Глаголы.<br>Настоящее время.</h2>
<div class="to-be-red">to be</div>
<button id="startBtn">Начать учиться 🐱</button>
</div>
`;
document.body.appendChild(modal);
document.getElementById('startBtn').addEventListener('click', () => {
modal.remove();
document.getElementById('gameContainer').style.display = 'block';
enableAudio();
resetGame();
});
}
showStart();
</script>
</body>
</html>