· Sharp.go Team
Внутри движка: как sharp.go рендерит 361 камень на 60fps
Пять лет назад доска для Го на 60 кадрах в секунду с полноценной 3D-инспекцией была мечтой рендерера. Сегодня это его дневная задача. Этот пост — тот самый разбор с комментариями, которого нам не хватало в начале: архитектурные решения, тупики и мелкие детали, которые всё изменили.
● Проблема
01Почему это сложно
Три ограничения, которые сформировали 3D-движок, который мы выпускаем сегодня.
Игра в Го — это дерево, а не линия. В любой момент игрок может разветвиться на тысячи альтернативных продолжений, и у каждого своя расстановка камней на сетке 19×19. Мы хотели всё три сразу: интерактивную 3D-камеру, задержку анализа меньше 100 мс и партию, которая не разваливается после 200-го хода.
Каждое из этих ограничений решаемо по отдельности. Проблема в том, что все они затрагивают один и тот же горячий путь — момент, когда камень касается доски — и каждому нужно разное время.
● Кодирование ходов
0221-байтный проводной формат
Компактный, детерминированный, воспроизводимый между версиями.
Каждый ход в sharp.go — это 21-байтная полезная нагрузка. Мы перепробовали JSON, CBOR и protobuf, прежде чем остановиться на самописном бинарном формате. Формат настолько компактен, что 400 ходов реальной игры занимают 8,4 КБ — примерно столько же, сколько сжатый JPEG самой доски.
- 01.
Байт 0 — Цвет
0x00 для чёрных, 0x01 для белых. Один байт. Без согласований.
- 02.
Байты 1–2 — Координата
Два байта в little-endian: строка (0–18) и столбец (0–18). 361 допустимая позиция на сетке 19×19.
- 03.
Байты 3–6 — Номер хода
32-битный индекс хода без знака. Последовательный внутри партии, детерминированный между воспроизведениями.
- 04.
Байты 7–10 — Метка реального времени
миллисекунды от начала игры. Используется для перемотки воспроизведения.
- 05.
Байты 11–14 — Хеш позиции
32-битный хеш Zobrist. Позволяет обнаруживать дублирующиеся позиции и суперко без полного сканирования доски.
- 06.
Байты 15–20 — Зарезервировано для сигналов движка
Захваченные камни, маркер ко, флаг пасса. Зарезервировано для прямой совместимости.
"
Мы не собирались изобретать бинарный формат. Мы хотели сделать анализ мгновенным, и число байтов оказалось самым простым ограничением, которое можно ослабить последним.
"

Ход 217 — чёрные играют расширение снизу. Один байт цвета, два байта координаты, восемнадцать байт контекста.
● Конвейер рендеринга
03Три прохода, один холст
Порядок важнее стоимости.
Рендерер — это строгий трёхпроходный конвейер. Мы не сортируем, не смешиваем и не отражаем между проходами — каждый проход пишет в свою текстуру, а следующий её читает.
● Tabs
● Дизайн-решения
04Почему мы выпускаем 3D первым
Логика нашего первого продукта, а не приговор 2D.
● Comparison
Сравнение движков
| ● Feature | sharp.go | 2D-клиенты | Мобильные приложения |
|---|---|---|---|
| 3D-инспекция доски | ✓ | ✗ | ✗ |
| Отклик ИИ быстрее 100 мс | ✓ | ✗ | ✓ |
| Открытый формат партий | ✓ | ✓ | ✗ |
| Совместный разбор | ✓ | ✗ | ✗ |
| Ссылки для шеринга в два клика | ✓ | ✗ | ✓ |
| Режим только в браузере | ✓ | ✗ | ✗ |
- ✓
Инстансный рендеринг по всей доске
361 инстанс, один вызов отрисовки. Всё остальное было медленнее.
- ✓
Кешированные отражения, а не реалтайм
Перерисовка при повороте камеры больше 5°. Игроки не замечают.
- ✓
Бинарный формат ходов на диске
Компактный, детерминированный — партии 2026 года загружаются и в 2027.
- ✓
Глубокие ссылки как URL первого класса
У каждой позиции стабильный URL. Поделиться доской — это копипаст, а не скриншот.
● Часто задаваемые вопросы
01 Почему движок использует Zobrist-хеширование для позиций? ▾
Хеши Zobrist обновляются за O(1) на каждый ход (xor изменённых битов) и позволяют обнаруживать суперко и дублирующиеся позиции за одно 32-битное сравнение. Полное сканирование доски на каждом ходу нормально работает на 19×19, но не масштабируется на 25×25, которые мы планируем поддерживать.
02 Можно ли воспроизвести партию по URL на другом устройстве? ▾
Да. У каждой партии есть стабильный URL с последовательностью ходов, закодированной в пути. Откройте URL на любом устройстве в любом браузере — и воспроизведение начнётся с той же позиции.
03 Играет ли ИИ на том же уровне офлайн? ▾
Да. Локальный ИИ работает полностью офлайн и по умолчанию откалиброван на уровень начинающего. В меню можно поднять уровень сильнее — никакого сетевого запроса не требуется.
04 Почему бинарный формат ходов не описан в публичной спецификации? ▾
Стабильность. Формат — часть нашего обещания совместимости воспроизведений. Мы опубликуем стабильную спецификацию v1, когда выйдет движок 1.0. До этого момента формат может меняться между минорными версиями.
● Что дальше
05Дорожная карта, а не обещания
Над чем мы работаем сейчас, в порядке ожидаемой стоимости.
Следующие шесть месяцев — о переносимости воспроизведений. Каждая сыгранная вами партия должна пережить клиент, на котором была сыграна.
● Попробовать движок
Сыграть на настоящей 3D-доске
Без установки. Откройте игру в браузере, сыграйте против откалиброванного ИИ, поделитесь позицией одним кликом.
"
Лучший интерфейс для Го — тот, который исчезает. Вы смотрите на доску, а не на приложение.
"