/
VeraEnglish
/
TypeGame
Обзор
Документация
Войти
/
VeraEnglish
/
TypeGame
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
index.html
94 строки
16 KB
Vera Ermolaeva
Create: index.html
04 авг 2026, 16:53
Верифицирован
04 авг 2026, 16:53
428c683
Код
Авторство
О чём код?
<!doctype html> <html lang="ru"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="description" content="Добрая игра для тренировки печати на русском и английском языках." /> <title>Спаси зверят!</title> <style> :root { --ink:#23334d; --blue:#80d2fb; --deep-blue:#3489c5; --grass:#71c76b; --yellow:#ffd55c; --coral:#ff886d; --card:#ffffffed; } * { box-sizing:border-box; } body { margin:0; min-width:320px; min-height:100vh; color:var(--ink); font-family:"Arial Rounded MT Bold","Trebuchet MS",Arial,sans-serif; background:linear-gradient(#8bd8ff 0 60%,#91d97d 60%); overflow-x:hidden; } body::before, body::after { content:"☁"; position:fixed; color:#fff9; font-size:8rem; z-index:-1; animation:float 9s ease-in-out infinite; } body::before { top:3vh; left:6vw; } body::after { top:16vh; right:8vw; font-size:5rem; animation-delay:-4s; } button, input { font:inherit; } button { border:0; cursor:pointer; } button:focus-visible, input:focus-visible { outline:4px solid #253b66; outline-offset:3px; } .sr-only { position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0; } .app { width:min(920px, calc(100% - 28px)); margin:0 auto; padding:24px 0 36px; } .brand { display:flex; align-items:center; justify-content:center; gap:10px; margin-bottom:16px; font-size:clamp(1.6rem,5vw,2.5rem); color:#fff; text-shadow:0 3px 0 #4784b0; } .card { background:var(--card); border:4px solid #fff; border-radius:28px; box-shadow:0 14px 0 #43845a33, 0 20px 30px #3a718a36; padding:clamp(22px,5vw,42px); text-align:center; } .screen { display:none; } .screen.active { display:block; animation:appear .35s ease-out; } h1, h2, p { margin-top:0; } h1 { font-size:clamp(2rem,7vw,3.3rem); margin-bottom:.35rem; } h2 { font-size:clamp(1.7rem,6vw,2.5rem); } .lead { font-size:clamp(1.05rem,3vw,1.3rem); line-height:1.5; max-width:600px; margin:0 auto 28px; } .language-grid, .topic-grid { display:grid; grid-template-columns:repeat(2, minmax(0,1fr)); gap:16px; max-width:680px; margin:auto; } .topic-grid { grid-template-columns:repeat(2, minmax(0,1fr)); } .choice { min-height:116px; padding:16px; border-radius:22px; color:var(--ink); background:#f7fcff; box-shadow:inset 0 0 0 3px #d7effb; font-size:1.2rem; font-weight:bold; transition:transform .15s, background .15s; } .choice:hover { transform:translateY(-4px); background:#fff3b9; } .choice .emoji { display:block; font-size:2.55rem; margin-bottom:5px; } .topbar { display:flex; justify-content:space-between; gap:14px; align-items:center; margin-bottom:15px; font-size:1.05rem; font-weight:bold; } .counter { background:#fff5bd; padding:9px 14px; border-radius:999px; } .back { background:#e7f5ff; color:var(--ink); padding:10px 14px; border-radius:999px; font-weight:bold; } .game-card { padding-top:24px; } .instruction { color:#527089; font-size:1.05rem; margin-bottom:10px; } .animal-zone { position:relative; min-height:188px; display:flex; align-items:center; justify-content:center; margin:0 auto 8px; overflow:hidden; background:linear-gradient(180deg,#e5f8ff 0 70%,#c8f0a9 70%); border-radius:22px; } .animal-zone::after { content:"🏠"; position:absolute; right:20px; bottom:18px; font-size:3.4rem; } .animal-zone::before { content:"🌲 🌲"; position:absolute; left:12px; bottom:18px; font-size:2.6rem; } .animal { font-size:6.4rem; line-height:1; z-index:1; filter:drop-shadow(0 8px 3px #355b5633); animation:bob 1.8s ease-in-out infinite; } .animal.saved { animation:run-home 1s ease-in forwards; } .word { font-size:clamp(2.5rem,10vw,4.1rem); letter-spacing:.05em; font-weight:bold; margin:16px 0 6px; color:#244b72; overflow-wrap:anywhere; } .letter-status { min-height:28px; margin-bottom:14px; font-size:1.2rem; letter-spacing:.14em; } .letter-status .good { color:#248450; } .letter-status .bad { color:#d84e54; text-decoration:underline wavy; } .answer { display:block; width:min(100%,520px); min-height:60px; margin:0 auto 10px; padding:12px 16px; border:3px solid #a8d9ef; border-radius:16px; color:var(--ink); font-size:1.35rem; text-align:center; background:white; } .answer.is-wrong { border-color:var(--coral); background:#fff3f1; } .answer.is-right { border-color:var(--grass); background:#effeea; } .message { min-height:28px; margin:4px 0 14px; font-size:1.05rem; font-weight:bold; } .message.error { color:#b44249; } .message.success { color:#197844; } .actions { display:flex; justify-content:center; flex-wrap:wrap; gap:12px; } .primary, .secondary { padding:14px 22px; border-radius:16px; min-height:54px; font-size:1.1rem; font-weight:bold; box-shadow:0 4px 0 #0002; } .primary { color:#513b00; background:var(--yellow); } .primary:hover { background:#ffe382; } .secondary { color:#174a30; background:#bcecb8; } .secondary:hover { background:#d2f7cd; } .result-icon { font-size:6rem; margin-bottom:6px; } .stars { color:#d99700; font-size:1.4rem; font-weight:bold; } .small-note { margin-top:26px; color:#557087; font-size:.95rem; } @keyframes bob { 50% { transform:translateY(-9px) rotate(3deg); } } @keyframes float { 50% { transform:translateX(35px) translateY(-13px); } } @keyframes appear { from { opacity:0; transform:translateY(10px); } } @keyframes run-home { 65% { transform:translateX(250px) scale(.72); opacity:1; } 100% { transform:translateX(340px) scale(.25); opacity:0; } } @media (max-width:540px) { .app { width:min(100% - 18px,920px); padding-top:12px; } .card { padding:22px 15px; border-radius:23px; } .language-grid,.topic-grid { gap:10px; } .choice { min-height:98px; padding:12px 7px; font-size:1rem; } .choice .emoji { font-size:2rem; } .topbar { flex-wrap:wrap; justify-content:center; } .animal-zone { min-height:160px; } .animal { font-size:5.4rem; } .actions { display:grid; } .actions button { width:100%; } } @media (prefers-reduced-motion:reduce) { *,*::before,*::after { animation-duration:.01ms !important; animation-iteration-count:1 !important; scroll-behavior:auto !important; } } </style> </head> <body> <main class="app"> <div class="brand" aria-label="Спаси зверят"><span>🐾</span><span id="brand-title">Спаси зверят!</span></div> <section id="home" class="screen active card" aria-labelledby="home-title"> <h1 id="home-title">Поможем зверятам?</h1><p class="lead">Выбери язык, печатай слова — и каждый зверёк найдёт дорогу домой!</p> <div class="language-grid"><button class="choice" data-lang="ru"><span class="emoji">🇷🇺</span>Русский</button><button class="choice" data-lang="en"><span class="emoji">🇬🇧</span>English</button></div> <p class="small-note">6 добрых заданий в каждом раунде</p> </section> <section id="topics" class="screen card" aria-labelledby="topics-title"> <button id="topics-back" class="back">← Назад</button><h2 id="topics-title">Выбери тему</h2><p id="topics-lead" class="lead">Какие слова будем печатать?</p><div id="topic-grid" class="topic-grid"></div> </section> <section id="game" class="screen card game-card" aria-labelledby="game-title"> <div class="topbar"><button id="game-back" class="back">← Темы</button><span id="star-counter" class="counter">⭐ 0</span><span id="progress" class="counter">Зверята: 1 / 6</span></div> <p id="game-title" class="instruction">Напечатай слово, чтобы помочь зверьку!</p> <div class="animal-zone"><div id="animal" class="animal" role="img" aria-label="Зверёк">🦊</div></div> <div id="word" class="word" aria-label="Слово для набора">лиса</div><div id="letter-status" class="letter-status" aria-live="polite"></div> <label id="answer-label" class="sr-only" for="answer">Напечатай слово</label><input id="answer" class="answer" type="text" autocomplete="off" autocapitalize="off" spellcheck="false" /> <div id="message" class="message" role="status" aria-live="polite"></div> <div class="actions"><button id="speak" class="secondary" type="button">🔊 Послушать слово</button><button id="hint" class="secondary" type="button">💡 Подсказка</button><button id="check" class="primary" type="button">Помочь зверьку</button></div> </section> <section id="result" class="screen card" aria-labelledby="result-title"> <div class="result-icon">🎉</div><h2 id="result-title">Все зверята спасены!</h2><p id="result-text" class="lead"></p><p id="result-stars" class="stars"></p><div class="actions"><button id="again" class="primary">Ещё раз</button><button id="change-topic" class="secondary">Другая тема</button><button id="main-menu" class="back">Главное меню</button></div> </section> </main> <script> const data = { ru: { title:'Спаси зверят!', chooseTopic:'Выбери тему', topicLead:'Какие слова будем печатать?', instruction:'Напечатай слово, чтобы помочь зверьку!', progress:'Зверята', placeholder:'Напечатай слово…', speak:'🔊 Послушать слово', hint:'💡 Подсказка', check:'Помочь зверьку', backTopics:'← Темы', back:'← Назад', almost:'💛 Почти получилось! Проверь слово ещё раз.', success:'✓ Отлично! Зверёк уже бежит домой!', result:'Все зверята спасены!', resultText:n => `Ты помог(ла) ${n} зверятам найти дорогу домой.`, again:'Ещё раз', change:'Другая тема', menu:'Главное меню', topics:{ animals:{name:'Животные',icon:'🐾',words:['кот','пёс','лев','лиса','сова','кит','ёж','волк']}, school:{name:'Школа',icon:'📚',words:['стол','книга','ручка','школа','доска','мяч','класс','пенал']}, fruits:{name:'Фрукты',icon:'🍎',words:['сок','груша','яблоко','банан','лимон','слива','арбуз','персик']}, transport:{name:'Транспорт',icon:'🚌',words:['авто','поезд','метро','лодка','такси','автобус','самолёт','велосипед']} } }, en: { title:'Save the Animals!', chooseTopic:'Choose a topic', topicLead:'Which words will we type?', instruction:'Type the word to help the animal!', progress:'Animals', placeholder:'Type the word…', speak:'🔊 Listen to the word', hint:'💡 Hint', check:'Help the animal', backTopics:'← Topics', back:'← Back', almost:'💛 Almost! Check the word and try again.', success:'✓ Great! The animal is going home!', result:'All animals are safe!', resultText:n => `You helped ${n} animals find their way home.`, again:'Play again', change:'New topic', menu:'Main menu', topics:{ animals:{name:'Animals',icon:'🐾',words:['cat','dog','lion','fox','owl','whale','hedgehog','wolf']}, school:{name:'School',icon:'📚',words:['desk','book','pen','school','board','ball','class','pencil']}, fruits:{name:'Fruit',icon:'🍎',words:['juice','pear','apple','banana','lemon','plum','melon','peach']}, transport:{name:'Transport',icon:'🚌',words:['car','train','metro','boat','taxi','bus','plane','bike']} } } }; const animals=['🐱','🐶','🦊','🦉','🦔','🐼','🐰','🐻']; const state={lang:'ru',topic:null,round:[],index:0,locked:false}; const $ = id => document.getElementById(id); const screens=['home','topics','game','result']; function show(id) { screens.forEach(x => $(x).classList.toggle('active',x===id)); } function shuffle(list) { return [...list].sort(()=>Math.random()-.5); } function normalize(value) { return value.trim().toLocaleLowerCase().replaceAll('ё','е'); } function copy() { return data[state.lang]; } function setLanguage(lang) { state.lang=lang; const t=copy(); $('brand-title').textContent=t.title; $('topics-title').textContent=t.chooseTopic; $('topics-lead').textContent=t.topicLead; $('topics-back').textContent=t.back; $('game-back').textContent=t.backTopics; $('game-title').textContent=t.instruction; $('answer-label').textContent=t.placeholder; $('answer').placeholder=t.placeholder; $('speak').textContent=t.speak; $('hint').textContent=t.hint; $('check').textContent=t.check; $('again').textContent=t.again; $('change-topic').textContent=t.change; $('main-menu').textContent=t.menu; renderTopics(); show('topics'); } function renderTopics() { const t=copy(); $('topic-grid').innerHTML=Object.entries(t.topics).map(([key,topic])=>`<button class="choice" data-topic="${key}"><span class="emoji">${topic.icon}</span>${topic.name}</button>`).join(''); } function startRound(topic) { state.topic=topic; state.round=shuffle(copy().topics[topic].words).slice(0,6); state.index=0; state.locked=false; show('game'); renderWord(); } function renderWord() { const t=copy(), word=state.round[state.index]; state.locked=false; $('animal').className='animal'; $('animal').textContent=animals[state.index%animals.length]; $('word').textContent=word; $('answer').value=''; $('answer').className='answer'; $('message').textContent=''; $('message').className='message'; $('letter-status').textContent=''; $('star-counter').textContent=`⭐ ${state.index}`; $('progress').textContent=`${t.progress}: ${state.index+1} / 6`; setTimeout(()=>$('answer').focus(),50); } function updateLetters() { const typed=$('answer').value, target=state.round[state.index]; if (!typed) { $('letter-status').textContent=''; $('answer').classList.remove('is-wrong'); return; } let html=''; for(let i=0;i<target.length;i++){ const char=target[i]; if(i<typed.length) html+=`<span class="${normalize(typed[i])===normalize(char)?'good':'bad'}">${char}</span>`; else html+=`<span>${char}</span>`; } $('letter-status').innerHTML=html; } function checkAnswer() { if(state.locked) return; const answer=$('answer').value; if(!answer.trim()) return; const t=copy(); if(normalize(answer)===normalize(state.round[state.index])) { state.locked=true; $('answer').classList.add('is-right'); $('message').textContent=t.success; $('message').className='message success'; $('animal').classList.add('saved'); $('star-counter').textContent=`⭐ ${state.index+1}`; setTimeout(()=>{ state.index++; if(state.index===state.round.length) showResult(); else renderWord(); },1050); } else { $('answer').classList.add('is-wrong'); $('message').textContent=t.almost; $('message').className='message error'; $('answer').focus(); } } function showHint() { if(state.locked) return; const typed=$('answer').value, target=state.round[state.index]; const position=Math.min(typed.length,target.length-1); $('message').textContent=`💡 ${target.slice(0, position+1)}…`; $('message').className='message'; } function speakWord() { if (state.locked || !('speechSynthesis' in window)) return; window.speechSynthesis.cancel(); const utterance=new SpeechSynthesisUtterance(state.round[state.index]); utterance.lang=state.lang==='ru'?'ru-RU':'en-US'; utterance.rate=.78; utterance.pitch=1.08; window.speechSynthesis.speak(utterance); } function showResult() { const t=copy(); $('result-title').textContent=t.result; $('result-text').textContent=t.resultText(state.round.length); $('result-stars').textContent=`⭐ ${state.round.length} / ${state.round.length} ⭐`; show('result'); } document.addEventListener('click', event => { const lang=event.target.closest('[data-lang]')?.dataset.lang, topic=event.target.closest('[data-topic]')?.dataset.topic; if(lang) setLanguage(lang); if(topic) startRound(topic); }); $('answer').addEventListener('input',()=>{ $('answer').classList.remove('is-wrong'); updateLetters(); }); $('answer').addEventListener('keydown',e=>{ if(e.key==='Enter') checkAnswer(); }); $('check').addEventListener('click',checkAnswer); $('speak').addEventListener('click',speakWord); $('hint').addEventListener('click',showHint); $('topics-back').addEventListener('click',()=>show('home')); $('game-back').addEventListener('click',()=>show('topics')); $('again').addEventListener('click',()=>startRound(state.topic)); $('change-topic').addEventListener('click',()=>show('topics')); $('main-menu').addEventListener('click',()=>show('home')); </script> </body> </html>