Кейс · Go-бэкенд
Пиксельная стена: общий холст
Совместный холст 256×256 в духе r/place: 16 цветов, кулдаун на сессию и IP, свой WebSocket-слой на stdlib (RFC 6455) с бинарным протоколом (4 бита на пиксель), снимок и дельты, снапшот плюс журнал с восстановлением, таймлапс, зум и пан, мини-карта, экспорт PNG, админ-инструменты. Пет-проект.
- Go
- stdlib only
- WebSocket
- Canvas 2D
- Vanilla JS
- embed
- Binary protocol
- Snapshot + journal
- Docker
- GitHub Actions
01 · Как выглядит
Скриншоты


02 · О проекте
Что это и зачем
«Пиксельная стена» — совместный пиксельный холст в духе r/place: 256×256, 16 цветов, один пиксель раз в несколько секунд на сессию. Изменения видны всем сразу по WebSocket, а история сохраняется и проигрывается таймлапсом. Пет-проект.
Только stdlib Go, без зависимостей и CGO; WebSocket-слой по RFC 6455 написан самостоятельно (взят из проекта realtime-rooms), клиент на ванильном JS и canvas встроен через embed. В демо-режиме есть нарисованный арт и несколько ботов, все они честно помечены.
Ограничения
Всё в одном процессе и на одном диске, горизонтально не масштабируется. Кулдауны, сессии и rate limit живут в памяти и сбрасываются при рестарте (баны сохраняются).
Сессия это идентификатор в localStorage: кто очистит хранилище, получит новую. Защита от простых ботов, а не от целенаправленной атаки с множества IP; за общим NAT лимит по IP делится на всех.
Журнал пишется без fsync на каждый пиксель, fsync раз в 30 секунд: при потере питания можно потерять последние секунды. Клиенту нужен DecompressionStream (Chrome 103+, Safari 16.4+, Firefox 113+).
Автоматических браузерных тестов в репозитории нет, интерфейс проверялся вручную в Edge. Тесты с -race проходят только в CI, Docker-образ не собирался.
Что внутри
- Свой WebSocket и бинарный протокол: клиент шлёт пиксель в 6 байтах, сервер рассылает дельты раз в 50 мс; новый клиент получает сжатый снимок и дальше только дельты
- Согласованность: снимок несёт seq, дельта несёт firstSeq, при пропуске клиент переподключается, а медленный клиент с переполненной очередью отключается
- Хранение 4 бита на пиксель (256×256 = 32 КиБ), снапшот на диск (crc32, fsync, rename) плюс журнал изменений
- Восстановление после падения: снапшот, затем записи журнала с большим seq, недописанный хвост обрезается; битый снапшот восстанавливается из журнала
- Кулдаун на сервере на сессию и на IP (скользящее окно), подписанные сессии, rate limit HTTP и WebSocket, проверка Origin, лимиты размеров сообщений и подключений
- Таймлапс по журналу: старый цвет в записи позволяет откатывать историю назад без базового снимка; скорости 1×, 4×, 16×
- Зум и пан (колесо, щипок, перетаскивание, клавиатура), мини-карта, счётчик онлайна, экспорт PNG и ?embed=1
- Админка по токену: очистка области, бан сессии или IP, просмотр последних установок; нагрузочный тест на 300 клиентов без пропусков дельт
03 · Как запустить
Запуск одной командой
git clone <репозиторий по запросу> pixel-wall
cd pixel-wall
SEED_DEMO=1 ADMIN_TOKEN=secret go run ./cmd/server # http://localhost:8103, админка на /?admin04 · Код
Репозиторий приватный
Исходники лежат в приватном репозитории. Открою доступ по запросу: напишите, и пришлю приглашение.
Запросить код