Как отлаживать веб-настолку с ИИ: пошаговый гайд
Практический гайд по вайб-дебагу браузерной карточной игры: от воспроизведения бага до проверки синхронизации. Без магии, только проверяемые шаги.
Вайб-дебаг — это отладка по внешним симптомам, когда код сгенерирован моделью и не до конца понятен. Ниже — набор действий, которые помогают находить причины багов в браузерной настолке. Гайд не про конкретный движок, а про метод.
Что понадобится
- Браузер с DevTools (Chrome, Firefox или Edge).
- Доступ к репозиторию и возможность запускать проект локально.
- Консоль с логами сервера и клиента.
- Два окна браузера или два устройства для проверки синхронизации.
- Список известных багов с шагами воспроизведения.
- Терпение: один баг — один эксперимент.
Шаг 1. Зафиксируйте баг в виде сценария
Открывайте DevTools (F12) и записывайте каждое действие. Пример сценария:
- Открыть игру в двух окнах.
- В окне A выбрать карту в руке.
- Перетащить её на стол.
- Отпустить.
- Проверить, появилась ли карта в окне B.
Если баг плавающий, добавьте в код временные логи. Например, в обработчик броска карты:
function onCardDrop(cardId, x, y) {
console.log('[drop]', { cardId, x, y, t: Date.now() });
sendMove({ type: 'playCard', cardId, x, y });
}
Логи должны быть с метками времени. Без них вы не отличите задержку сети от ошибки рендера.
Шаг 2. Отделите визуальную часть от сетевой
Проблема может быть в отрисовке, в передаче данных или в правилах. Проверяйте по очереди.
Сначала проверьте, приходит ли событие на сервер. В консоли сервера добавьте лог входящих сообщений:
ws.on('message', (raw) => {
const msg = JSON.parse(raw);
console.log('[ws in]', msg.type, msg);
});
Если сообщение приходит, но карта не появляется у соперника — ищите ошибку в рассылке или в клиентском обработчике. Если сообщение не приходит — смотрите клиентский код отправки.

Шаг 3. Проверьте состояние доски до и после хода
Сделайте снимок состояния (state) до и после действия. В клиенте можно вывести его в консоль:
function dumpState(label) {
console.log(label, JSON.stringify(gameState, null, 2));
}
Вызывайте dumpState('before') перед ходом и dumpState('after') после. Сравнивайте поля: позиция карты, чей ход, счёт. Если состояние меняется не там, где ожидалось, — баг в логике правил.
Шаг 4. Воспроизведите ход вручную через консоль
Если баг не повторяется мышью, отправьте событие напрямую. Это помогает отделить UI от логики. Пример для WebSocket-соединения:
const ws = new WebSocket('ws://localhost:8080');
ws.onopen = () => {
ws.send(JSON.stringify({ type: 'playCard', cardId: 'card-1', x: 100, y: 200 }));
};
Адрес и формат сообщения возьмите из кода клиента. Если при ручной отправке всё работает, проблема в обработчике мыши или в вычислении координат.

Шаг 5. Проверьте синхронизацию двух клиентов
Откройте два окна. В каждом выполните в консоли:
console.log('client id', window.clientId);
Если clientId не определён, добавьте его при подключении. Затем сравните состояние после одного и того же хода. Рассинхрон часто вызван тем, что один клиент применяет ход локально, а второй ждёт сервер. Проверьте, не дублируется ли применение.
Шаг 6. Изолируйте правила игры в отдельную функцию
Правила должны быть чистыми функциями: на входе состояние и ход, на выходе новое состояние. Пример:
function applyMove(state, move) {
if (move.type !== 'playCard') return state;
const next = structuredClone(state);
next.table.push({ cardId: move.cardId, x: move.x, y: move.y });
next.turn = state.turn === 'A' ? 'B' : 'A';
return next;
}
Такую функцию легко тестировать без браузера. Напишите несколько вызовов в консоли и проверьте результат. Если правила работают в изоляции, но ломаются в игре — ищите, где состояние мутируется вне функции.
Шаг 7. Смотрите на швы между движениями
В статье автор замечает, что видит не карту, а швы между движениями. Это признак того, что анимация и логика живут отдельно. Проверьте, не запускается ли анимация до подтверждения сервера. Если да, возможны рывки при откате. Решение — оптимистичное обновление с откатом по ответу сервера. Но сначала убедитесь, что ответ приходит.
Типичные ошибки и как их узнать
- Логи без меток времени. Вы не отличите задержку сети от медленного рендера. Добавьте
Date.now()в каждый лог. - Проверка только на одном клиенте. Синхронизация не проверена. Всегда открывайте два окна.
- Мутация состояния в обработчике. Симптом: после отмены хода состояние не возвращается. Ищите прямые присваивания вместо создания копии.
- Смешение UI и правил. Симптом: баг воспроизводится только при определённом размере окна. Вынесите правила в отдельные функции.
- Игнорирование порядка сообщений. Симптом: карта появляется у одного игрока раньше, чем у другого. Проверьте, не отправляются ли события параллельно без очереди.
Если данных о конкретной причине нет, не гадайте. Сначала соберите логи, потом меняйте код. Один эксперимент — одна гипотеза.