Браузерний тренажер сліпого десятипальцевого набору для української (ЙЦУКЕН) та англійської (QWERTY). Задуманий як система навчання, а не як гра на швидкість: програма має три етапи, кожна клавіша закріплена за одним пальцем, а після кожної спроби учень бачить рівно одну наступну дію. Поверх навчання є ігровий шар: рівень, серія днів, перегони в реальному часі, групи й рейтинги.
- Гра: https://typing-race-rosy.vercel.app
- Код: https://github.com/prodelt/typing-race-hackathon
- Автоматичні перевірки (CI): https://github.com/prodelt/typing-race-hackathon/actions
- Контакт: stoliarenko.my@gmail.com
- Путівник для журі й агентів-рецензентів (вимога → де реалізовано → чим доведено): docs/jury-guide.md
Для кого: для тих, хто вчиться друкувати не дивлячись на клавіатуру, за комп’ютером із фізичною клавіатурою (від 1024 px завширшки; на вужчому екрані навчання каже, що потрібна клавіатура, а профіль, рейтинги й перегони можна переглянути).
- Етап 1, гами. Механічні вправи для пальців на вже відкритих клавішах: пробіги домашнім рядом, дзеркальні пари, чергування рук, ізоляція одного пальця, вертикальні переходи, Shift і цифри, метроном. Текст гам породжується з карти пальців, а не пишеться вручну.
- Етап 2, слова з відкритих клавіш. Слова зі словників, складені лише з клавіш, які учень уже засвоїв.
- Етап 3, Академія. Модулі з частотних біграм, морфем і темпу, кожен із видимим прогресом і критерієм завершення.
Клавіша відкривається, коли на вправі, де вона є фокусом, три залікові спроби поспіль мають точність не нижчу за планку. Швидкість нічого не відкриває й нічого не блокує. Залікова спроба йде без підказок, тренувальна з підказками й не рахується. Помилка, виправлена Backspace, лишається в статистиці. Після спроби екран результату показує метрики, помилки за символами, ритм, порівняння з попереднім результатом і одну наступну дію. Є керований сеанс на 15–25 хвилин із чотирьох блоків (розминка, головна навичка, закріплення, справжній текст), повторення слабких клавіш і переходів та вільне повторення будь-якої відкритої вправи. Докладно й з обґрунтуваннями: docs/pedagogy.md.
- Мапа навчання: три етапи як один маршрут, вузол на кожен блок вправ.
- Ігровий шар: рівень і XP за залікові спроби, серія днів із заморозкою, сезон. XP дають лише успішні залікові спроби, тож шар не винагороджує швидкість без точності.
- Перегони в реальному часі: швидкий пошук суперника й приватні кімнати за кодом. Рейтинг перегонів (Elo) рахує сервер за результатами справжніх перегонів. Якщо розкладка ОС не збігається з розкладкою тексту, заїзд не приймає літер; застосунок помічає це з надрукованих літер і пояснює причину, а не мовчки стоїть.
- Групи й таблиці лідерів, лише з нікнеймом: ім’я, пошта й аватар Google ніколи не показуються.
- Необов’язковий акаунт Google. Навчання повністю локальне й ніколи не потребує входу. Увійшовши, учень переносить спроби, налаштування й нік на інший пристрій. У налаштуваннях є «видалити мої дані». Рішення: ADR-0006.
- Доступність і налаштування: три теми (світла, темна, для слабкого зору), рух і звук вимикаються, розмір тексту вправи від 24 до 40 px, керування з клавіатури, дві мови інтерфейсу.
- Без мережі: service worker дає працювати після першого завантаження.
- Сторінки «Формули» (як рахуються SPM, точність, ритм), «Ліцензії» (джерела даних і шрифтів), «Приватність» і «Про проєкт».
Навчання, метрики й прогрес працюють у браузері без сервера. Сервер потрібен лише для перегонів, груп, рейтингів і входу; коли його немає, ці розділи про це кажуть, а навчання нічого не помічає.
apps/web односторінковий застосунок (Vite + React 19), екрани лежать у src/features
packages/engine автомат вправи: життєвий цикл спроби, шлях натискання
packages/metrics SPM, точність, ритм, затримки: чисті функції без API браузера й Node
packages/curriculum карти пальців, гами, порядок відкриття, правила майстерності, ігрові правила
packages/domain спільні типи
packages/ui компоненти дизайн-системи
data/ похідні дані словників (слова, n-грами) і навчальні матеріали
supabase/ міграції (PostgreSQL з RLS), конфігурація Auth, Edge Functions
tools/data відтворюваний конвеєр обробки словників
e2e/ сценарії Playwright
Рішення, що визначають архітектуру, зведено в docs/adr/: шлях натискання лежить
поза React (0002), спроби незмінні й мають
UUID клієнта (0004), metrics і curriculum не знають
про браузер, щоб той самий код рахував і на сервері (0005).
Чесна серверна частина:
- Метрики спроби перераховує сервер з журналу натискань (Edge Function
submit-attempt), а результат перегонівfinish-raceне бере з клієнта: він програє журнал проти тексту кімнати тим самим кодомpackages/metrics, що й браузер. Рейтинг рахує сервер. - RLS увімкнено на кожній таблиці, функції мають ліміти запитів,
supabase db advisorsна живому проєкті не показує помилок. Видалення акаунта:delete-account. - Заголовки на Vercel: CSP, що діє (не лише звітує), HSTS на два роки,
X-Frame-Options: DENY, суворийReferrer-Policy.
| Вибір | Чому |
|---|---|
| Vite + React 19, SPA, TanStack Router | клієнтський рендер; шлях натискання лежить поза React |
Прихований textarea + beforeinput/compositionend |
єдиний шлях, що читає кирилицю в усіх браузерах і який можна автоматизувати; keydown лише для часу |
| Zustand і власні типізовані редьюсери | життєвому циклу вправи вистачає написаного вручну редьюсера; XState не використано |
| Tailwind + CSS-змінні | дизайн-система Ametrin (варіант b-red); три теми це набори змінних |
| Paraglide | українська та англійська, типізовані повідомлення |
| Supabase (PostgreSQL, Auth, Realtime, Edge Functions) | перегони, групи, рейтинги, вхід через Google; розгортання фронтенду на Vercel |
| Biome | один інструмент на лінт і форматування |
| Vitest, fast-check, Playwright | властивісні тести для формул; справжні події клавіатури в браузері |
| Самостійно розміщені шрифти | без звернень до сторонніх серверів, працює без мережі (data-sources) |
Потрібні Node 24.19.0 і pnpm (версія закріплена в packageManager; corepack enable підтягне її).
Для навчання не потрібні ні змінні середовища, ні Docker, ні акаунти.
pnpm install
pnpm dev # сервер розробки
pnpm build # production-збірка; на ній ганяються e2e
pnpm preview # показати production-збірку локальноЩоб працювали перегони, групи й вхід, потрібен проєкт Supabase: скопіюйте .env.example у
.env.local і задайте VITE_SUPABASE_URL та VITE_SUPABASE_ANON_KEY до pnpm build (обидва
значення публічні за задумом: ключ захищає RLS, а не таємниця). Налаштування бекенду крок за кроком
описано в .env.example.
pnpm check # typecheck + lint + модульні тести
pnpm typecheck # tsc --noEmit по всьому робочому простору
pnpm lint # Biome
pnpm test # Vitest: модульні й властивісні тести
pnpm data:check # перезібрати словники в пам’яті й порівняти з закоміченими
pnpm test:e2e # Playwright, Chromium, разом з аудитом доступності axe
pnpm test:e2e:input # шлях вводу в Chromium, Firefox і WebKit
pnpm test:e2e:cdp # сценарій зі змодельованою фізичною розкладкою ЙЦУКЕН (лише Chromium)
pnpm test:latency # затримка від натискання до малюванняПерший запуск e2e потребує pnpm exec playwright install --with-deps.
pnpm data і pnpm data:check читають сирий знімок словників організаторів у
tasks/Typing-Race-2026-Hackathon/dictionaries/ (його не комітимо). У чистому клоні без знімка
data:check завершується з кодом 2 й нічого не перевіряє; закомічені дані при цьому все одно
перевіряє pnpm test: тести банків слів читають лише data/derived/ (немає нецензурних слів,
чужих літер, перелічених русизмів; частота й контрольні суми збігаються зі звітом). Три перевірки
§8.6–8.8 (кодування, контрольні суми сировини, відтворюваність) доводяться й без знімка: тест
tools/data/pipeline.synthetic.test.ts сам пише крихітний знімок із справжнім CHECKSUMS.sha256 і
проганяє через нього весь конвеєр.
GitHub Actions на кожному pull request і пуші в main ганяє чотири job:
- checks: typecheck, lint, модульні тести, збірка з бюджетом початкового JS;
- e2e: усі сценарії в Chromium, сценарії з реальними подіями клавіатури через CDP, шлях вводу додатково у Firefox і WebKit;
- e2e against a local Supabase:
supabase startпіднімає з міграцій і функцій цього репозиторію Postgres, Auth, REST, Realtime і Edge-середовище; застосунок збирається проти нього, і біжать сценарії@backend(групи, синхронізація, перегони на двох браузерах, у тому числі на реальних клавішах) та набір атак на сервер. До живого проєкту CI не звертається ніколи; - secret scan: gitleaks.
Станом на 2026-10-03: 758 модульних і властивісних тестів, 270 сценаріїв e2e в Chromium (42 з них,
позначені @backend, біжать у job із локальним Supabase) і 6 у проєкті CDP. Початковий JS у
production-збірці: 147,0 КБ gzip при бюджеті 150 КБ, який ламає збірку в разі перевищення; запас
малий, тож нове в початковий бандл вносимо лише ліниво. Lighthouse (десктоп) на розгорнутому сайті за
аудитом 2026-10-02: 100/100/100/100 на Головній, Мапі, екрані вправи й Профілі, на «Про гру»
98/100/100/100. Сценарій демонстрації для журі
(§9 специфікації) пройдено одним тестом e2e/jury.spec.ts; кожен основний екран перевіряється на
1024×768 без бокового скролу й порушень доступності. Що саме захищено й чим перевірено:
docs/security.md.
Сценарії @backend локально з .env.local (живий URL) створили б тестові акаунти в живому проєкті;
для перевірки без бекенду використовуйте pnpm exec playwright test --grep-invert @backend.
- Лише дві розкладки: ЙЦУКЕН і QWERTY. Мобільного навчання немає: потрібна фізична клавіатура.
- Браузер не каже, яка розкладка ОС активна. Ні
getLayoutMap(), ні події зміни розкладки цього не дають, тож застосунок виводить її з літер, які учень надрукував. Перед стартом він просить натиснути літеру, а в перегонах на хибній розкладці пояснює, чому курсор не рухається. Автоматичні тести не можуть перемкнути розкладку ОС; ґ й апостроф на macOS не перевірено на справжньому Mac (docs/pedagogy.md). - Клавіші, яких немає у вправах. Схема пальців QWERTY малює лише клавіші, що виробляють
підтримувані символи.
[,],/і клавіша зворотного апострофа за таблицею вимог належать правому мізинцю, але в схемі їх немає, бо жодна вправа їх не вживає. - Другий пристрій гостя. Якщо увійти в акаунт Google, який уже має дані, спроби цього пристрою додаються до нього, а перегони анонімного гостя лишаються під його гостьовим ніком і не зливаються (ADR-0006).
- Немає експорту й імпорту прогресу файлом (прогрес переноситься входом через Google), редактора власного курсу, додаткових розкладок.
- Затримку «натискання → кадр» вимірює
pnpm test:latency, але в headless-середовищі нижня межа виміру близько 15–17 мс, тож вимогу «менше 16 мс» там не довести; JS займає близько 1 мс на натискання.
Слова Етапу 2 і 3 беруться з наданих організаторами знімків відкритих словників після очищення
скриптом pnpm data; похідні дані лежать у data/derived/ і поширюються за CC BY-SA 4.0,
сирі знімки не комітяться. Джерела, їхні ліцензії та спосіб використання:
docs/data-sources.md, у застосунку сторінка «Ліцензії». Шрифти розміщено
самостійно, їхні ліцензії теж у docs/data-sources.md.
Проєкт створено однією людиною разом з агентом Claude Code. Агент планував, писав код, тести й документи, людина ухвалювала рішення. У самому застосунку ШІ не використовується: базові уроки, вправи й рекомендації обчислюються правилами без жодної моделі. Повна декларація з перевіркою: docs/ai-use.md.
| Документ | Про що |
|---|---|
| docs/jury-guide.md | карта для рецензента: умови §11, перевірки §8, сценарій §9, критерії §10 з посиланнями на файли й тести |
| docs/pedagogy.md | чому програма вчить саме так: палець на клавішу, етапи, лічба помилок, режим без підглядання |
| docs/data-sources.md | джерела вмісту, їхні ліцензії, заміри, шрифти |
| docs/security.md | модель загрози, шари захисту, два набори атак, знахідки й виправлення, чого немає |
| docs/ai-use.md | декларація про використання ШІ |
| docs/adr/ | чинні рішення: скоуп, шлях вводу, метрики, архітектура, акаунт |
| docs/research/ | звіти досліджень із посиланнями на першоджерела |
| CONTEXT.md | словник предметної області |
| CLAUDE.md | інструкція для агентів: як організована робота |
Документи для агентів (CLAUDE.md, docs/adr/, CONTEXT.md) англійською; документи для журі українською.
Планувальні артефакти першої половини роботи — карта рішень із 24 тікетами, конституція, п’ять
пакетів Spec Kit — заархівовано 2026-09-30 у git-тег archive/process-harness-2026-09-30. Вони
описували процес, а не продукт; чинні рішення з них зведено в docs/adr/.
Код розповсюджується за ліцензією MIT: LICENSE. Похідні дані в data/derived/ мають
власну ліцензію, CC BY-SA 4.0; ліцензії шрифтів і джерел даних:
docs/data-sources.md.