chore: восстановление репозитория из снапшота v0.3.1

Прежняя git-история утрачена при переносе проекта на машину владельца
(снапшот без .git). Хэши коммитов в docs/reports/* относятся к утраченной
истории.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
sab.code.lab 2026-08-07 09:34:02 +02:00
commit 1c85091186
184 changed files with 33303 additions and 0 deletions

View file

@ -0,0 +1,116 @@
<!doctype html>
<html lang="ru" data-theme="light">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Кабинет — Иго · школа Го</title>
<meta
name="description"
content="Вход в кабинет школы Го: синхронизация прогресса между устройствами."
/>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=PT+Sans:wght@400;700&family=PT+Serif:wght@400;700&family=PT+Mono&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<header class="site-header">
<div class="container">
<a class="logo" href="index.html"><span class="kanji"></span> Иго · школа Го</a>
<nav class="main-nav" aria-label="Основное меню">
<ul>
<li><a href="learn.html">Курс</a></li>
<li><a href="tsumego.html">Цумэ-го</a></li>
<li><a href="play.html">Играть</a></li>
<li><a href="progress.html">Прогресс</a></li>
<li><a href="cabinet.html" aria-current="page">Кабинет</a></li>
</ul>
</nav>
<div class="header-actions">
<button class="menu-toggle" type="button" aria-label="Открыть меню" aria-expanded="false">
</button>
</div>
</div>
</header>
<main>
<div class="container">
<!-- состояние: гость -->
<div class="card auth-card" data-logged-out>
<h1>Вход в кабинет</h1>
<p style="text-align: center; color: var(--ink-soft); font-size: 0.95rem">
Кабинет нужен только для синхронизации прогресса между устройствами. Без него всё
работает так же.
</p>
<form data-login-form novalidate>
<div class="field">
<label for="email">Электронная почта</label>
<input
type="email"
id="email"
name="email"
autocomplete="email"
placeholder="you@example.com"
/>
<span class="error-text">Введите корректный адрес почты.</span>
</div>
<div class="field">
<label for="password">Пароль</label>
<input
type="password"
id="password"
name="password"
autocomplete="current-password"
placeholder="••••••••"
/>
<span class="error-text">Пароль не может быть пустым.</span>
</div>
<button class="btn btn--primary" type="submit" style="width: 100%">Войти</button>
</form>
<div class="auth-links">
<span>Нет аккаунта? <a href="register.html">Зарегистрируйтесь</a></span>
<a href="register.html">Забыли пароль?</a>
</div>
</div>
<!-- состояние: вы вошли -->
<div class="card auth-card logged-in" data-logged-in hidden>
<h1>Вы вошли</h1>
<p class="email" data-user-email>you@example.com</p>
<p style="color: var(--ink-soft); font-size: 0.95rem">
Прогресс пока на этом устройстве. Нажмите синхронизацию, чтобы забрать его с собой.
</p>
<div class="btn-row" style="justify-content: center">
<button class="btn btn--primary" type="button" data-sync>
Синхронизировать прогресс
</button>
<button class="btn btn--danger" type="button" data-logout>Выйти</button>
</div>
</div>
</div>
</main>
<footer class="site-footer">
<div class="container">
<span class="privacy-note"
>◎ Без сбора данных: прогресс хранится только на вашем устройстве.</span
>
<nav aria-label="Меню в подвале">
<ul>
<li><a href="learn.html">Курс</a></li>
<li><a href="tsumego.html">Цумэ-го</a></li>
<li><a href="play.html">Играть</a></li>
<li><a href="cabinet.html">Кабинет</a></li>
</ul>
</nav>
<span>© 2026 Иго</span>
</div>
</footer>
<script src="js/main.js"></script>
</body>
</html>

View file

@ -0,0 +1,166 @@
<!doctype html>
<html lang="ru" data-theme="light">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Иго — научитесь играть в Го с нуля</title>
<meta
name="description"
content="Камерная школа Го (вэйци, бадук) на русском: курс с нуля до 10 кю, цумэ-го с проверкой, партии против ИИ шести уровней."
/>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=PT+Sans:wght@400;700&family=PT+Serif:wght@400;700&family=PT+Mono&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<header class="site-header">
<div class="container">
<a class="logo" href="index.html"><span class="kanji"></span> Иго</a>
<nav class="main-nav" aria-label="Основное меню">
<ul>
<li><a href="learn.html">Курс</a></li>
<li><a href="tsumego.html">Цумэ-го</a></li>
<li><a href="play.html">Играть</a></li>
<li><a href="progress.html">Прогресс</a></li>
<li><a href="cabinet.html">Кабинет</a></li>
</ul>
</nav>
<div class="header-actions">
<button class="menu-toggle" type="button" aria-label="Открыть меню" aria-expanded="false">
</button>
</div>
</div>
</header>
<main>
<section class="hero">
<div class="container">
<div>
<span class="hero-kicker">вэйци · бадук · го</span>
<h1>Научитесь играть <em>в&nbsp;Го</em> с&nbsp;нуля</h1>
<p class="lead">
Спокойный курс без регистрации-принуждения: теория, задачи с проверкой на доске и
партии против компьютера — от первых камней до уверенного 10&nbsp;кю.
</p>
<div class="btn-row">
<a class="btn btn--primary" href="learn.html">Начать курс</a>
<a class="btn" href="play.html">Сыграть с ИИ</a>
</div>
<div class="hero-meta">
<div class="item"><strong>10</strong><span>разделов курса</span></div>
<div class="item"><strong>12</strong><span>задач цумэ-го</span></div>
<div class="item"><strong>6</strong><span>уровней ИИ</span></div>
</div>
</div>
<figure class="hero-figure">
<span class="hero-chip"><span class="dot"></span> Ваш ход — E5</span>
<img
src="assets/hero.jpg"
alt="Деревянный гобан с несколькими чёрными и белыми камнями в начальной позиции"
width="1024"
height="576"
/>
<figcaption>Гобан, сланец и ракушка — три тысячи лет той же партии.</figcaption>
</figure>
</div>
</section>
<section class="features">
<div class="container">
<div class="section-head">
<div>
<p class="kicker">как это работает</p>
<h2>Как устроено обучение</h2>
</div>
<p>
Три простые вещи, которые вместе дают рост: теория малыми дозами, задачи до
автоматизма и живая практика.
</p>
</div>
<div class="features-grid">
<div class="card feature-card">
<span class="icon"></span>
<h3>С нуля, по шагам</h3>
<p>
Десять разделов: от дамэ и атари до дзёсэки и ёсэ. Короткие уроки, схемы позиций,
никакой воды — только то, что работает на доске.
</p>
</div>
<div class="card feature-card">
<span class="icon"></span>
<h3>Задачи с проверкой</h3>
<p>
Жизнь и смерть, сэмэаи, лестницы. Фильтры по теме и сложности, решённые отмечаются
автоматически — видно, что уже в опоре.
</p>
</div>
<div class="card feature-card">
<span class="icon"></span>
<h3>Партии с ИИ, 6 уровней</h3>
<p>
Доски 9×9, 13×13 и 19×19, коми, отмена хода и подсказки трёх лучших ходов. Начните с
первого уровня — он терпелив.
</p>
</div>
</div>
<div class="ink-band">
<figure>
<img
src="assets/ink.jpg"
alt="Позиция на углу гобана в манере тушевой живописи суми-э"
loading="lazy"
/>
<figcaption>
Угол доски, тушь и пустое пространство — эстетика ма, в которой учится глаз.
</figcaption>
</figure>
</div>
<div class="home-strip">
<figure class="hero-figure">
<img
src="assets/stones.jpg"
alt="Чёрные сланцевые и белые ракушечные камни Го в деревянных чашах"
loading="lazy"
/>
</figure>
<div class="card quote">
<blockquote>
«Го — это игра, которую легко выучить и невозможно исчерпать».
</blockquote>
<cite>— старая пословица. Проверьте на себе: первый урок занимает десять минут.</cite>
<p style="margin-top: 24px">
<a class="btn btn--quiet" href="lesson.html">Первый урок: дамэ и захват →</a>
</p>
</div>
</div>
</div>
</section>
</main>
<footer class="site-footer">
<div class="container">
<span class="privacy-note"
>◎ Без сбора данных: прогресс хранится только на вашем устройстве.</span
>
<nav aria-label="Меню в подвале">
<ul>
<li><a href="learn.html">Курс</a></li>
<li><a href="tsumego.html">Цумэ-го</a></li>
<li><a href="play.html">Играть</a></li>
<li><a href="cabinet.html">Кабинет</a></li>
</ul>
</nav>
<span>© 2026 Иго</span>
</div>
</footer>
<script src="js/main.js"></script>
</body>
</html>

View file

@ -0,0 +1,193 @@
<!doctype html>
<html lang="ru" data-theme="light">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Курс — Иго · школа Го</title>
<meta
name="description"
content="Программа курса Го с нуля до 10 кю: десять разделов от дамэ и захвата до простого ёсэ."
/>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=PT+Sans:wght@400;700&family=PT+Serif:wght@400;700&family=PT+Mono&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<header class="site-header">
<div class="container">
<a class="logo" href="index.html"><span class="kanji"></span> Иго · школа Го</a>
<nav class="main-nav" aria-label="Основное меню">
<ul>
<li><a href="learn.html" aria-current="page">Курс</a></li>
<li><a href="tsumego.html">Цумэ-го</a></li>
<li><a href="play.html">Играть</a></li>
<li><a href="progress.html">Прогресс</a></li>
<li><a href="cabinet.html">Кабинет</a></li>
</ul>
</nav>
<div class="header-actions">
<button class="menu-toggle" type="button" aria-label="Открыть меню" aria-expanded="false">
</button>
</div>
</div>
</header>
<main>
<div class="page-head">
<div class="container">
<p class="kicker">с нуля до 10 кю</p>
<h1>Программа курса</h1>
<p>
Десять разделов, каждый — короткая теория и задачи на доске. Идите по порядку: каждый
раздел опирается на предыдущий. Отметки «пройден» сохраняются на вашем устройстве.
</p>
</div>
</div>
<div class="container">
<div class="course-grid">
<a class="card card--link lesson-card" href="lesson.html" data-lesson-card="dame">
<span class="lesson-num">1</span>
<div>
<h3>Дамэ и захват</h3>
<p>
Дыхания группы, постановка камня на доску, как камни снимаются с доски. Самый первый
урок — с него начинается всё.
</p>
<div class="meta"><span class="badge">10 мин</span><span data-done-slot></span></div>
</div>
</a>
<a class="card card--link lesson-card" href="lesson.html" data-lesson-card="atari">
<span class="lesson-num">2</span>
<div>
<h3>Атари, лестница, сеть</h3>
<p>
Угроза захвата и три способа её реализовать: прямое атари, ситэтя (лестница) и гэтэ
(сеть).
</p>
<div class="meta"><span class="badge">15 мин</span><span data-done-slot></span></div>
</div>
</a>
<a class="card card--link lesson-card" href="lesson.html" data-lesson-card="ko">
<span class="lesson-num">3</span>
<div>
<h3>Самоубийство и ко</h3>
<p>
Запрещённые пункты, правило ко и ко-угрозы. Почему партия не может повторяться
бесконечно.
</p>
<div class="meta"><span class="badge">12 мин</span><span data-done-slot></span></div>
</div>
</a>
<a class="card card--link lesson-card" href="lesson.html" data-lesson-card="eyes">
<span class="lesson-num">4</span>
<div>
<h3>Глаза: жизнь и смерть</h3>
<p>
Два глаза — жизнь. Настоящие и ложные глаза, базовые формы: прямая четвёрка, гнутая
тройка, косяк.
</p>
<div class="meta"><span class="badge">20 мин</span><span data-done-slot></span></div>
</div>
</a>
<a class="card card--link lesson-card" href="lesson.html" data-lesson-card="scoring">
<span class="lesson-num">5</span>
<div>
<h3>Подсчёт и конец партии</h3>
<p>
Территория и пленники, коми, два паса, мёртвые камни. Как понять, кто победил, не
считая на пальцах.
</p>
<div class="meta"><span class="badge">15 мин</span><span data-done-slot></span></div>
</div>
</a>
<a class="card card--link lesson-card" href="lesson.html" data-lesson-card="connect">
<span class="lesson-num">6</span>
<div>
<h3>Связь и разрезание</h3>
<p>Крепкие и тонкие связи, точки разрезания, защита своих слабостей и атака чужих.</p>
<div class="meta"><span class="badge">15 мин</span><span data-done-slot></span></div>
</div>
</a>
<a class="card card--link lesson-card" href="lesson.html" data-lesson-card="corners">
<span class="lesson-num">7</span>
<div>
<h3>Углы, стороны, центр</h3>
<p>
Почему партия начинается в углах, ценность третьей и четвёртой линии, первые
принципы фусэки.
</p>
<div class="meta"><span class="badge">15 мин</span><span data-done-slot></span></div>
</div>
</a>
<a class="card card--link lesson-card" href="lesson.html" data-lesson-card="joseki">
<span class="lesson-num">8</span>
<div>
<h3>Базовые дзёсэки</h3>
<p>
Установленные последовательности в углу: хоси-кэима, комоку и три простейших дзёсэки
наизусть.
</p>
<div class="meta"><span class="badge">25 мин</span><span data-done-slot></span></div>
</div>
</a>
<a class="card card--link lesson-card" href="lesson.html" data-lesson-card="shape">
<span class="lesson-num">9</span>
<div>
<h3>Форма</h3>
<p>
Хорошие и плохие формы: тигровая пасть, бамбуковый стык, пустой треугольник и почему
его избегают.
</p>
<div class="meta"><span class="badge">20 мин</span><span data-done-slot></span></div>
</div>
</a>
<a class="card card--link lesson-card" href="lesson.html" data-lesson-card="yose">
<span class="lesson-num">10</span>
<div>
<h3>Простое ёсэ</h3>
<p>
Эндшпиль без боли: сэнтэ и готэ, ценность ходов, типичные завершения на границе
территорий.
</p>
<div class="meta"><span class="badge">20 мин</span><span data-done-slot></span></div>
</div>
</a>
</div>
</div>
</main>
<footer class="site-footer">
<div class="container">
<span class="privacy-note"
>◎ Без сбора данных: прогресс хранится только на вашем устройстве.</span
>
<nav aria-label="Меню в подвале">
<ul>
<li><a href="learn.html">Курс</a></li>
<li><a href="tsumego.html">Цумэ-го</a></li>
<li><a href="play.html">Играть</a></li>
<li><a href="cabinet.html">Кабинет</a></li>
</ul>
</nav>
<span>© 2026 Иго</span>
</div>
</footer>
<script src="js/main.js"></script>
</body>
</html>

View file

@ -0,0 +1,184 @@
<!doctype html>
<html lang="ru" data-theme="light">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Урок 1. Дамэ и захват — Иго · школа Го</title>
<meta
name="description"
content="Первый урок курса Го: дыхания группы, дамэ, постановка и снятие камней с доски."
/>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=PT+Sans:wght@400;700&family=PT+Serif:wght@400;700&family=PT+Mono&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<header class="site-header">
<div class="container">
<a class="logo" href="index.html"><span class="kanji"></span> Иго · школа Го</a>
<nav class="main-nav" aria-label="Основное меню">
<ul>
<li><a href="learn.html" aria-current="page">Курс</a></li>
<li><a href="tsumego.html">Цумэ-го</a></li>
<li><a href="play.html">Играть</a></li>
<li><a href="progress.html">Прогресс</a></li>
<li><a href="cabinet.html">Кабинет</a></li>
</ul>
</nav>
<div class="header-actions">
<button class="menu-toggle" type="button" aria-label="Открыть меню" aria-expanded="false">
</button>
</div>
</div>
</header>
<main>
<div class="page-head">
<div class="container container--narrow">
<p class="kicker">урок 1 из 10</p>
<h1>Дамэ и захват</h1>
<p>
Десять минут — и вы будете знать главное правило Го. Всё остальное в игре растёт из
него.
</p>
</div>
</div>
<div class="container">
<article class="lesson-body">
<h2>Камень живёт, пока дышит</h2>
<p>
Камни ставятся на <strong>пересечения линий</strong>, а не в клетки. Поставленный камень
не двигается — он либо остаётся на доске до конца партии, либо снимается при захвате.
</p>
<p>
Соседние пункты по линиям — это <strong>дамэ</strong>, дыхания камня. У камня в центре
четыре дыхания, на стороне — три, в углу — два.
</p>
<pre>
· ─ · ─ ·
│ │ │
· ─ ○ ─ · у белого камня
│ │ │ четыре дамэ: слева, справа,
· ─ · ─ · сверху и снизу</pre>
<p class="diagram-caption">Диаграмма 1. Четыре дыхания камня в центре доски.</p>
<p>
Камни одного цвета, стоящие рядом по линиям, образуют <strong>группу</strong> — они
делят дыхания и живут или умирают вместе.
</p>
<h2>Атари и захват</h2>
<p>
Когда у группы остаётся последнее дыхание, говорят <strong>«атари»</strong>
предупреждение об угрозе. Если противник занимает последнее дамэ, группа
<strong>снимается с доски</strong> и становится пленниками.
</p>
<pre>
· ─ ● ─ ·
│ │ │
● ─ ○ ─ · белый в атари: осталось
│ │ │ одно дамэ справа
· ─ ● ─ ·</pre>
<p class="diagram-caption">Диаграмма 2. Чёрные поставили белого в атари.</p>
<pre>
· ─ ● ─ ·
│ │ │
● ─ ● ← · чёрные заняли последнее дамэ —
│ │ │ белый камень снят с доски
· ─ ● ─ ·</pre>
<p class="diagram-caption">Диаграмма 3. Захват: пленник уходит в чашу чёрных.</p>
<div class="try-it">
<div
class="goban-static"
data-size="9"
data-black="d4,c5,e5,d6"
data-white="d5"
data-mark="e4"
></div>
<div>
<p class="label">Попробуйте сами</p>
<p>
Белый камень на D5 в атари. Куда чёрным поставить камень, чтобы снять его с доски?
Отметка подсказывает район — найдите точное пересечение, а затем
<a href="play.html">проверьте себя в игре против ИИ</a>.
</p>
</div>
</div>
<h2>Зачем это знать</h2>
<p>
Вся тактика Го — игра с дыханиями: вы сокращаете дамэ чужих групп и бережёте свои.
Лестница, сеть, сэмэаи, жизнь и смерть — всё это про дыхания, которые мы разберём в
следующих уроках.
</p>
<p>
Запомните три числа: <strong>432</strong>. Столько дыханий у одинокого камня в центре,
на стороне и в углу. Поэтому угол и умирает быстрее всех — и поэтому же там проще всего
строить территорию, но об этом в седьмом уроке.
</p>
<div class="try-it">
<div
class="goban-static"
data-size="9"
data-black="b2,c2"
data-white="b3,c3,a2"
data-last="a2"
></div>
<div>
<p class="label">Попробуйте сами</p>
<p>
Два белых камня стоят группой. Сколько дамэ у этой группы? Посчитайте все пустые
соседние пункты обоих камней — общие дыхания считаются один раз.
</p>
</div>
</div>
<h2>Кратко</h2>
<p>
Камни ставятся на пересечения и не двигаются. Дыхания (дамэ) — соседние пустые пункты.
Последнее дамэ занято — группа снята. Дальше:
<a href="lesson.html">атари, лестница и сеть</a>.
</p>
<div class="lesson-nav">
<a class="btn btn--quiet" href="learn.html">Все разделы</a>
<button class="btn btn--primary" type="button" data-lesson-done="dame">
Отметить пройденным
</button>
<a class="btn" href="lesson.html">Урок 2: атари →</a>
</div>
</article>
</div>
</main>
<footer class="site-footer">
<div class="container">
<span class="privacy-note"
>◎ Без сбора данных: прогресс хранится только на вашем устройстве.</span
>
<nav aria-label="Меню в подвале">
<ul>
<li><a href="learn.html">Курс</a></li>
<li><a href="tsumego.html">Цумэ-го</a></li>
<li><a href="play.html">Играть</a></li>
<li><a href="cabinet.html">Кабинет</a></li>
</ul>
</nav>
<span>© 2026 Иго</span>
</div>
</footer>
<script src="js/main.js"></script>
</body>
</html>

View file

@ -0,0 +1,161 @@
<!doctype html>
<html lang="ru" data-theme="light">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Играть против ИИ — Иго · школа Го</title>
<meta
name="description"
content="Партия Го против компьютера: доски 9×9, 13×13 и 19×19, шесть уровней ИИ, подсказки трёх лучших ходов."
/>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=PT+Sans:wght@400;700&family=PT+Serif:wght@400;700&family=PT+Mono&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<header class="site-header">
<div class="container">
<a class="logo" href="index.html"><span class="kanji"></span> Иго · школа Го</a>
<nav class="main-nav" aria-label="Основное меню">
<ul>
<li><a href="learn.html">Курс</a></li>
<li><a href="tsumego.html">Цумэ-го</a></li>
<li><a href="play.html" aria-current="page">Играть</a></li>
<li><a href="progress.html">Прогресс</a></li>
<li><a href="cabinet.html">Кабинет</a></li>
</ul>
</nav>
<div class="header-actions">
<button class="menu-toggle" type="button" aria-label="Открыть меню" aria-expanded="false">
</button>
</div>
</div>
</header>
<main>
<div class="page-head">
<div class="container">
<p class="kicker">партия против компьютера</p>
<h1>Играть</h1>
<p>
Нажмите на пересечение, чтобы поставить камень. ИИ играет по правилам с захватом,
запретом самоубийства и простым ко.
</p>
</div>
</div>
<div class="container">
<div class="play-layout">
<div class="board-wrap">
<svg id="goban" role="application" aria-label="Игровая доска Го"></svg>
</div>
<aside class="play-panel">
<div class="card">
<h2>Настройки партии</h2>
<div class="settings-grid">
<div class="field">
<label for="board-size">Доска</label>
<select id="board-size" name="board-size">
<option value="9" selected>9 × 9</option>
<option value="13">13 × 13</option>
<option value="19">19 × 19</option>
</select>
</div>
<div class="field">
<label for="ai-level">Уровень ИИ</label>
<select id="ai-level" name="ai-level">
<option value="1">1 — новичок</option>
<option value="2" selected>2 — ученик</option>
<option value="3">3 — любитель</option>
<option value="4">4 — крепкий</option>
<option value="5">5 — сильный</option>
<option value="6">6 — мастер</option>
</select>
</div>
<div class="field">
<label for="color">Ваш цвет</label>
<select id="color" name="color">
<option value="black" selected>Чёрные</option>
<option value="white">Белые</option>
</select>
</div>
<div class="field">
<label for="komi">Коми</label>
<select id="komi" name="komi">
<option value="0">0</option>
<option value="5.5">5,5</option>
<option value="6.5" selected>6,5</option>
<option value="7.5">7,5</option>
</select>
</div>
</div>
</div>
<div class="card">
<h2>Пленники</h2>
<div class="captures">
<span class="side"
><span class="stone-dot black"></span> Чёрные взяли:
<strong data-captures="black">0</strong></span
>
<span class="side"
><span class="stone-dot white"></span> Белые взяли:
<strong data-captures="white">0</strong></span
>
</div>
</div>
<div class="status-line" data-status role="status">Новая партия. Ваш ход.</div>
<div class="card">
<h2>Три лучших хода</h2>
<ul class="hints-list" data-hints></ul>
</div>
<div class="card">
<h2>Управление</h2>
<div class="btn-row">
<button class="btn btn--small" type="button" data-action="pass">Пас</button>
<button class="btn btn--small btn--quiet" type="button" data-action="undo">
Отменить ход
</button>
<button class="btn btn--small btn--danger" type="button" data-action="resign">
Сдаться
</button>
<button class="btn btn--small btn--primary" type="button" data-action="new">
Новая партия
</button>
</div>
</div>
</aside>
</div>
</div>
</main>
<footer class="site-footer">
<div class="container">
<span class="privacy-note"
>◎ Без сбора данных: прогресс хранится только на вашем устройстве.</span
>
<nav aria-label="Меню в подвале">
<ul>
<li><a href="learn.html">Курс</a></li>
<li><a href="tsumego.html">Цумэ-го</a></li>
<li><a href="play.html">Играть</a></li>
<li><a href="cabinet.html">Кабинет</a></li>
</ul>
</nav>
<span>© 2026 Иго</span>
</div>
</footer>
<script src="js/main.js"></script>
<script src="js/go.js"></script>
</body>
</html>

View file

@ -0,0 +1,105 @@
<!doctype html>
<html lang="ru" data-theme="light">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Прогресс — Иго · школа Го</title>
<meta
name="description"
content="Ваш прогресс в школе Го: пройденные уроки, решённые задачи, серия дней."
/>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=PT+Sans:wght@400;700&family=PT+Serif:wght@400;700&family=PT+Mono&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<header class="site-header">
<div class="container">
<a class="logo" href="index.html"><span class="kanji"></span> Иго · школа Го</a>
<nav class="main-nav" aria-label="Основное меню">
<ul>
<li><a href="learn.html">Курс</a></li>
<li><a href="tsumego.html">Цумэ-го</a></li>
<li><a href="play.html">Играть</a></li>
<li><a href="progress.html" aria-current="page">Прогресс</a></li>
<li><a href="cabinet.html">Кабинет</a></li>
</ul>
</nav>
<div class="header-actions">
<button class="menu-toggle" type="button" aria-label="Открыть меню" aria-expanded="false">
</button>
</div>
</div>
</header>
<main>
<div class="page-head">
<div class="container">
<p class="kicker">тихий счёт упорству</p>
<h1>Прогресс</h1>
<p>
Всё считается локально, на этом устройстве. Ничего не отправляется на сервер — поэтому
цифры честные.
</p>
</div>
</div>
<div class="container" data-stats data-total-lessons="10" data-total-problems="12">
<div class="stats-grid">
<div class="card stat-card">
<div class="value" data-stat="lessons">0 / 10</div>
<div class="label">уроков пройдено</div>
</div>
<div class="card stat-card">
<div class="value" data-stat="problems">0 / 12</div>
<div class="label">задач решено</div>
</div>
<div class="card stat-card">
<div class="value" data-stat="streak">1</div>
<div class="label">дней подряд</div>
</div>
</div>
<div class="card" style="max-width: 640px">
<h2 style="margin-bottom: 14px">Путь по курсу</h2>
<div class="progress-track" role="progressbar" aria-label="Прогресс курса">
<div class="progress-fill"></div>
</div>
<p class="progress-note" data-stat="pct">Курс пройден на 0%</p>
<p class="progress-note">
Десять минут в день надёжнее трёх часов раз в месяц: Го растёт на регулярности, а не на
подвигах.
</p>
<div class="btn-row" style="margin-top: 16px">
<a class="btn btn--primary" href="learn.html">Продолжить курс</a>
<a class="btn btn--quiet" href="tsumego.html">К задачам</a>
</div>
</div>
</div>
</main>
<footer class="site-footer">
<div class="container">
<span class="privacy-note"
>◎ Без сбора данных: прогресс хранится только на вашем устройстве.</span
>
<nav aria-label="Меню в подвале">
<ul>
<li><a href="learn.html">Курс</a></li>
<li><a href="tsumego.html">Цумэ-го</a></li>
<li><a href="play.html">Играть</a></li>
<li><a href="cabinet.html">Кабинет</a></li>
</ul>
</nav>
<span>© 2026 Иго</span>
</div>
</footer>
<script src="js/main.js"></script>
</body>
</html>

View file

@ -0,0 +1,135 @@
<!doctype html>
<html lang="ru" data-theme="light">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Регистрация — Иго · школа Го</title>
<meta
name="description"
content="Регистрация в школе Го для синхронизации прогресса между устройствами."
/>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=PT+Sans:wght@400;700&family=PT+Serif:wght@400;700&family=PT+Mono&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<header class="site-header">
<div class="container">
<a class="logo" href="index.html"><span class="kanji"></span> Иго · школа Го</a>
<nav class="main-nav" aria-label="Основное меню">
<ul>
<li><a href="learn.html">Курс</a></li>
<li><a href="tsumego.html">Цумэ-го</a></li>
<li><a href="play.html">Играть</a></li>
<li><a href="progress.html">Прогресс</a></li>
<li><a href="cabinet.html" aria-current="page">Кабинет</a></li>
</ul>
</nav>
<div class="header-actions">
<button class="menu-toggle" type="button" aria-label="Открыть меню" aria-expanded="false">
</button>
</div>
</div>
</header>
<main>
<div class="container">
<div class="card auth-card">
<h1>Регистрация</h1>
<p style="text-align: center; color: var(--ink-soft); font-size: 0.95rem">
Одна учётная запись — чтобы прогресс жил на всех устройствах. Никакой рассылки.
</p>
<form data-login-form novalidate>
<div class="field">
<label for="email">Электронная почта</label>
<input
type="email"
id="email"
name="email"
autocomplete="email"
placeholder="you@example.com"
/>
<span class="error-text">Введите корректный адрес почты.</span>
</div>
<div class="field">
<label for="password">Пароль</label>
<input
type="password"
id="password"
name="password"
autocomplete="new-password"
placeholder="минимум 8 символов"
/>
<span class="error-text">Пароль не может быть пустым.</span>
</div>
<div class="field">
<label for="password2">Пароль ещё раз</label>
<input
type="password"
id="password2"
name="password2"
autocomplete="new-password"
placeholder="повторите пароль"
/>
<span class="error-text">Пароли не совпадают.</span>
</div>
<div class="field">
<label for="captcha">Код с картинки</label>
<div class="captcha-row">
<span class="captcha-box" data-captcha></span>
<button
class="btn btn--quiet btn--small"
type="button"
data-captcha-refresh
aria-label="Обновить код"
>
↻ обновить
</button>
</div>
<input
type="text"
id="captcha"
name="captcha"
inputmode="text"
autocomplete="off"
placeholder="символы с картинки"
style="margin-top: 10px"
/>
<span class="error-text">Введите код с картинки.</span>
</div>
<button class="btn btn--primary" type="submit" style="width: 100%">
Создать аккаунт
</button>
</form>
<div class="auth-links">
<span>Уже есть аккаунт? <a href="cabinet.html">Войдите</a></span>
</div>
</div>
</div>
</main>
<footer class="site-footer">
<div class="container">
<span class="privacy-note"
>◎ Без сбора данных: прогресс хранится только на вашем устройстве.</span
>
<nav aria-label="Меню в подвале">
<ul>
<li><a href="learn.html">Курс</a></li>
<li><a href="tsumego.html">Цумэ-го</a></li>
<li><a href="play.html">Играть</a></li>
<li><a href="cabinet.html">Кабинет</a></li>
</ul>
</nav>
<span>© 2026 Иго</span>
</div>
</footer>
<script src="js/main.js"></script>
</body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,340 @@
<!doctype html>
<html lang="ru" data-theme="light">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Цумэ-го — Иго · школа Го</title>
<meta
name="description"
content="Задачи цумэ-го с фильтрами по теме и сложности: жизнь и смерть, сэмэаи, лестницы, захват."
/>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=PT+Sans:wght@400;700&family=PT+Serif:wght@400;700&family=PT+Mono&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<header class="site-header">
<div class="container">
<a class="logo" href="index.html"><span class="kanji"></span> Иго · школа Го</a>
<nav class="main-nav" aria-label="Основное меню">
<ul>
<li><a href="learn.html">Курс</a></li>
<li><a href="tsumego.html" aria-current="page">Цумэ-го</a></li>
<li><a href="play.html">Играть</a></li>
<li><a href="progress.html">Прогресс</a></li>
<li><a href="cabinet.html">Кабинет</a></li>
</ul>
</nav>
<div class="header-actions">
<button class="menu-toggle" type="button" aria-label="Открыть меню" aria-expanded="false">
</button>
</div>
</div>
</header>
<main>
<div class="page-head">
<div class="container">
<p class="kicker">жизнь и смерть в миниатюре</p>
<h1>Цумэ-го</h1>
<p>
Задачи на локальную тактику. Ход чёрных — если не сказано иное. Решайте в уме, затем
проверяйте на доске в разделе «Играть».
</p>
</div>
</div>
<div class="container">
<form class="card filters" data-tsumego-filters aria-label="Фильтры задач">
<div class="field">
<label for="f-theme">Тема</label>
<select id="f-theme" name="theme">
<option value="all">Все темы</option>
<option value="life">Жизнь и смерть</option>
<option value="capture">Захват</option>
<option value="ladder">Лестницы</option>
<option value="semeai">Сэмэаи</option>
</select>
</div>
<div class="field">
<label for="f-diff">Сложность</label>
<select id="f-diff" name="difficulty">
<option value="all">Любая</option>
<option value="1">★ 1 — разминка</option>
<option value="2">★ 2 — легко</option>
<option value="3">★ 3 — средне</option>
<option value="4">★ 4 — трудно</option>
<option value="5">★ 5 — для упёртых</option>
</select>
</div>
<div class="field">
<label for="f-status">Статус</label>
<select id="f-status" name="status">
<option value="all">Все</option>
<option value="unsolved">Нерешённые</option>
<option value="solved">Решённые</option>
</select>
</div>
<div class="field">
<button class="btn btn--quiet btn--small" type="reset">Сбросить</button>
</div>
</form>
<div class="problems-grid">
<div
class="card problem-card"
data-problem="p01"
data-theme="capture"
data-difficulty="1"
>
<div class="thumb">
<div
class="goban-static"
data-size="9"
data-black="d4,c5,e5"
data-white="d5"
data-mark="d6"
></div>
</div>
<h3>Последнее дыхание</h3>
<div class="meta">
<span class="stars"><span class="off">★★★★</span></span
><span data-solved-slot></span>
</div>
</div>
<div
class="card problem-card"
data-problem="p02"
data-theme="capture"
data-difficulty="1"
>
<div class="thumb">
<div
class="goban-static"
data-size="9"
data-black="b2,c3,b4"
data-white="b3"
data-mark="a3"
></div>
</div>
<h3>Камень у края</h3>
<div class="meta">
<span class="stars"><span class="off">★★★★</span></span
><span data-solved-slot></span>
</div>
</div>
<div class="card problem-card" data-problem="p03" data-theme="life" data-difficulty="2">
<div class="thumb">
<div
class="goban-static"
data-size="9"
data-black="b2,c2,d2,b3,d3,b4,c4"
data-white="c3,d4"
data-mark="e3"
></div>
</div>
<h3>Один глаз или два?</h3>
<div class="meta">
<span class="stars">★★<span class="off">★★★</span></span
><span data-solved-slot></span>
</div>
</div>
<div class="card problem-card" data-problem="p04" data-theme="ladder" data-difficulty="2">
<div class="thumb">
<div
class="goban-static"
data-size="9"
data-black="e5,f4"
data-white="e4,f5,g6"
data-mark="d4"
></div>
</div>
<h3>Лестница работает?</h3>
<div class="meta">
<span class="stars">★★<span class="off">★★★</span></span
><span data-solved-slot></span>
</div>
</div>
<div class="card problem-card" data-problem="p05" data-theme="life" data-difficulty="3">
<div class="thumb">
<div
class="goban-static"
data-size="9"
data-black="b2,c2,d2,e2,b3,e3"
data-white="c3,d3,b4,c4,d4,e4"
data-mark="c5"
></div>
</div>
<h3>Гнутая четвёрка</h3>
<div class="meta">
<span class="stars">★★★<span class="off">★★</span></span
><span data-solved-slot></span>
</div>
</div>
<div class="card problem-card" data-problem="p06" data-theme="semeai" data-difficulty="3">
<div class="thumb">
<div
class="goban-static"
data-size="9"
data-black="d3,d4,d5,e5"
data-white="e3,e4,f4,f5"
data-mark="c4"
></div>
</div>
<h3>Гонка на захват</h3>
<div class="meta">
<span class="stars">★★★<span class="off">★★</span></span
><span data-solved-slot></span>
</div>
</div>
<div
class="card problem-card"
data-problem="p07"
data-theme="capture"
data-difficulty="3"
>
<div class="thumb">
<div
class="goban-static"
data-size="9"
data-black="c4,d3,e4,d5"
data-white="d4,c5"
data-mark="e5"
></div>
</div>
<h3>Сеть вместо лестницы</h3>
<div class="meta">
<span class="stars">★★★<span class="off">★★</span></span
><span data-solved-slot></span>
</div>
</div>
<div class="card problem-card" data-problem="p08" data-theme="ladder" data-difficulty="4">
<div class="thumb">
<div
class="goban-static"
data-size="9"
data-black="e5,f4,g3"
data-white="e4,f5,c7"
data-mark="d3"
></div>
</div>
<h3>Лестница с приманкой</h3>
<div class="meta">
<span class="stars">★★★★<span class="off"></span></span
><span data-solved-slot></span>
</div>
</div>
<div class="card problem-card" data-problem="p09" data-theme="semeai" data-difficulty="4">
<div class="thumb">
<div
class="goban-static"
data-size="9"
data-black="c3,d3,e3,c4,e4"
data-white="c5,d5,e5,d4"
data-mark="f4"
></div>
</div>
<h3>Четыре против трёх</h3>
<div class="meta">
<span class="stars">★★★★<span class="off"></span></span
><span data-solved-slot></span>
</div>
</div>
<div class="card problem-card" data-problem="p10" data-theme="life" data-difficulty="5">
<div class="thumb">
<div
class="goban-static"
data-size="9"
data-black="b2,c2,d2,e2,f2,b3,f3"
data-white="c3,d3,e3,b4,c4,d4,e4,f4"
data-mark="g3"
></div>
</div>
<h3>Шесть в углу живут?</h3>
<div class="meta"><span class="stars">★★★★★</span><span data-solved-slot></span></div>
</div>
<div
class="card problem-card"
data-problem="p11"
data-theme="capture"
data-difficulty="2"
>
<div class="thumb">
<div
class="goban-static"
data-size="9"
data-black="d6,e5"
data-white="d5,e6,f6"
data-mark="c5"
></div>
</div>
<h3>Двойное атари</h3>
<div class="meta">
<span class="stars">★★<span class="off">★★★</span></span
><span data-solved-slot></span>
</div>
</div>
<div class="card problem-card" data-problem="p12" data-theme="life" data-difficulty="1">
<div class="thumb">
<div
class="goban-static"
data-size="9"
data-black="b2,c2,d2,b4,c4,d4"
data-white="b3,c3,d3"
data-mark="e3"
></div>
</div>
<h3>Прямая тройка</h3>
<div class="meta">
<span class="stars"><span class="off">★★★★</span></span
><span data-solved-slot></span>
</div>
</div>
</div>
<div class="empty-state" data-empty-state style="display: none">
<span class="glyph">○ ●</span>
<p>
<strong>Под фильтры ничего не подошло.</strong><br />Ослабьте условия — или отметьтесь в
разделе «Прогресс», если решили всё.
</p>
</div>
</div>
</main>
<footer class="site-footer">
<div class="container">
<span class="privacy-note"
>◎ Без сбора данных: прогресс хранится только на вашем устройстве.</span
>
<nav aria-label="Меню в подвале">
<ul>
<li><a href="learn.html">Курс</a></li>
<li><a href="tsumego.html">Цумэ-го</a></li>
<li><a href="play.html">Играть</a></li>
<li><a href="cabinet.html">Кабинет</a></li>
</ul>
</nav>
<span>© 2026 Иго</span>
</div>
</footer>
<script src="js/main.js"></script>
</body>
</html>

View file

@ -0,0 +1,61 @@
# Дизайн: вход через VK ID и Яндекс ID (этап 8.2, запланирован)
Дата: 2026-08-06. Статус: дизайн (реализация — отдельной командой, когда
владелец получит ключи). Оба провайдера — российские юрлица; зарубежные
провайдеры исключены решением владельца.
## Что нужно от владельца (действия вне репозитория)
1. **VK ID**: кабинет https://id.vk.com/business/go → создать приложение
(веб-сайт) → получить `client_id` и `client_secret` (secure key) →
указать redirect URI: `https://<домен>/api/oauth/vk/callback.php`.
2. **Яндекс ID**: https://oauth.yandex.ru → новое приложение → права:
«Доступ к адресу электронной почты» (login:email), при желании
«имя и аватарка» → получить `ClientID`/`Client secret` → redirect
URI: `https://<домен>/api/oauth/yandex/callback.php`.
3. Вписать ключи в `config.php` на хостинге (не в репо!):
`'vk_client_id'`, `'vk_client_secret'`, `'yandex_client_id'`,
`'yandex_client_secret'`.
4. Домен обязан быть на HTTPS — оба провайдера требуют https redirect
URI (включается панелью хостинга, не .htaccess).
## Архитектура (когда будем делать)
- Таблица `oauth_accounts(user_id INTEGER, provider TEXT
('vk'|'yandex'), provider_user_id TEXT, PRIMARY KEY(provider,
provider_user_id))`; связь с users — по email (провайдер отдаёт
подтверждённый email → ищем/создаём users-запись, пароль при этом
NULL-able или случайный хэш — вход по паролю для такой учётки
отключён до установки пароля через «сменить пароль»).
- Эндпоинты: `GET /api/oauth/<provider>/start.php` → 302 на
авторизацию провайдера (state = random в сессии, anti-CSRF);
`GET /api/oauth/<provider>/callback.php?code&state` → проверка state
→ обмен code на token (server-side, client_secret в теле POST) →
получение email (VK: метод id.vk.com/oauth2/user_info; Яндекс:
https://login.yandex.ru/info?format=json с Bearer) → find-or-create
user + oauth_accounts → сессия → 302 на /account.html.
- VK ID — OAuth 2.1 + PKCE (code_verifier/code_challenge в сессии);
Яндекс — классический OAuth 2.0 code flow.
- Кнопки «Войти через VK ID» / «Войти через Яндекс ID» на /account.html
и /register.html; официальные бренд-ресурсы кнопок — из пресс-китов
провайдеров (лицензии — в CREDITS.md).
- Rate limit на start/callback; ошибки провайдера → /account.html с
тихой пометкой «вход через … не удался».
## Правовые заметки (не юридическая консультация)
- VK ID и Яндекс ID — сервисы российских юрлиц (ООО «В Контакте»,
ООО «Яндекс»); требование владельца «без зарубежной аутентификации»
соблюдено.
- 152-ФЗ: email/идентификаторы — персональные данные; при целевой
аудитории РФ рекомендуется хостинг с серверами в РФ и уведомление
Роскомнадзора как оператора ПДн (если применимо к проекту — вопрос
к юристу; сайт учебный, без монетизации).
- В privacy-заметку сайта (если появится) — перечислить, что храним:
email, хэш пароля, прогресс обучения.
## Объём реализации (оценка этапа 8.2)
server/: oauth/start+callback ×2 провайдера, миграция oauth_accounts,
smoke (моки token/userinfo через GOLEARN_TEST-хук); apps/web: кнопки,
строки; docs: обновить deploy.md (шаги ключей). ~1 сессия.