Полный рефакторинг проекта в стабильную расширяемую базу рогалика. Почему: после разнесения single-file на модули потерялся вызов генерации карты (RoomMap не генерировал комнаты) → игра падала на старте; баг скрывался тем, что Bun-бандлер не проверяет типы. Архитектура: - Логика игры (src/core/) полностью отделена от рендера: без three.js и DOM, тестируется без браузера. - Рендер мира на three.js с ортокамерой (2D-вид); HUD/миникарта — 2D-канвас поверх. - Фиксированный игровой цикл 60 Гц + интерполяция (раньше скорость зависела от частоты кадров). - Seeded-RNG, ввод через абстрактные «намерения» (InputState). Возможности: - Стартовое меню с выбором уровня (Esc → меню). - Конфигуратор уровней: LevelRules + 5 пресетов (размер карты, плотность/сила врагов, HP, фиксированный seed). - Тема внешнего вида (render/theme.ts) — задел под кастомные ассеты. Качество: - 27 юнит-тестов ядра (генерация, симметрия дверей, коллизии, спавн, правила). - Два круга adversarial-ревью; исправлено 6 реальных багов (кнокбэк сквозь стены → софт-лок; незакрываемая сокровищница; фикс-сид после рестарта; перенос ввода между забегами; нет source maps; неточности в доках). - Документация: README, docs/ARCHITECTURE.md, CLAUDE.md, docs/HOWTO.md. - dist/ исключён из гита; bun.lock зафиксирован. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dungeon Crawl — рогалик в духе The Binding of Isaac
Top-down рогалик: процедурный данжен из комнат, два режима боя (дальний/ближний), враги, босс. Логика на чистом TypeScript, рендер — на three.js (ортографическая камера, картинка плоская 2D-сверху). Сборка — Bun.
Есть стартовое меню с выбором уровня: данжен генерируется процедурно каждый забег, но параметризуется набором правил (размер, плотность/сила врагов, HP, seed). Внешний вид мира вынесен в «тему» — задел под кастомные ассеты (спрайты/текстуры).
Это рабочая база для развития, а не готовая игра. Архитектура специально сделана так, чтобы её было легко расширять — и человеку, и ИИ-агентам. Перед доработкой прочитай
CLAUDE.mdиdocs/HOWTO.md.
Быстрый старт
bun install # поставить зависимости (three, typescript)
bun run dev # дев-сервер с авто-пересборкой → http://localhost:3000
Продакшн-сборка:
bun run build # минифицированный бандл → dist/ (открой dist/index.html)
Проверки (запускай перед любым коммитом):
bun run typecheck # tsc --noEmit, строгий режим
bun test # юнит-тесты ядра
bun run check # и то, и другое разом
Управление
| Клавиша | Действие |
|---|---|
| WASD | движение |
| Стрелки | прицельная стрельба/удар в направлении |
| Пробел | атака по ходу движения |
| Tab / Q | сменить оружие (Дальний ↔ Ближний) |
| R | заново (на экране Game Over / Victory) |
| Esc | вернуться в меню выбора уровня |
Чтобы перейти в соседнюю комнату — зачисти текущую (двери откроются) и встань на дверь, нажимая в её сторону.
Режимы боя
| Режим | Оружие | Скорость | Урон | Особенность |
|---|---|---|---|---|
| Дальний | пистолет | быстро (cd 10) | 1 за выстрел | снаряды летят по прямой |
| Ближний | нож | медленно (cd 22) | 2 + отбрасывание | широкий взмах |
Типы комнат
| Тип | Описание |
|---|---|
| spawn | старт, врагов нет |
| normal | 2–4 врага |
| treasure | без врагов (комната-награда), сразу открыта |
| boss | 1 босс; его зачистка = победа |
Стек и устройство
- Bun — рантайм, бандлер и тест-раннер.
- three.js — WebGL-рендер мира через ортокамеру.
- TypeScript (strict) — весь код.
- Архитектура: логика игры полностью отделена от рендера. Ядро (
src/core/) не знает ни про DOM, ни про three.js, поэтому его легко тестировать и при желании можно подменить рендер, не трогая игру.
Подробности — в docs/ARCHITECTURE.md.
Структура проекта
src/
├── config.ts ⭐ КОНСТАНТЫ движка: размеры, геометрия дверей, базовый баланс
├── main.ts точка входа: меню → игра, «склейка» логики/рендера/ввода
├── core/ ── ИГРОВАЯ ЛОГИКА (без DOM и three.js) ──
│ ├── Game.ts «мозг»: состояние + один шаг симуляции step()
│ ├── rules.ts ⭐ ПРАВИЛА УРОВНЯ (пресеты для меню: размер, враги, HP, seed)
│ ├── types.ts общие типы (Dir, RoomType, Box, …)
│ ├── rng.ts ГПСЧ с seed (детерминизм для тестов/отладки)
│ ├── util.ts мат-утилиты (dist, overlap, clamp, lerp)
│ ├── entities/ Player, Enemy, Projectile, MeleeSwing
│ ├── world/ Room, RoomMap (генерация), tiles
│ └── systems/ collision, spawner (чистые функции)
├── input/ ── ВВОД ──
│ ├── InputState.ts абстрактные «намерения» (не сырые клавиши)
│ └── KeyboardController.ts клавиатура → InputState
├── render/ ── РЕНДЕР (читает состояние, рисует) ──
│ ├── Renderer.ts интерфейс рендера
│ ├── ThreeRenderer.ts мир на three.js (ортокамера)
│ ├── theme.ts ⭐ ВНЕШНИЙ ВИД (цвета; задел под спрайты/текстуры)
│ └── HudOverlay.ts HUD и миникарта на 2D-канвасе поверх
├── ui/
│ └── StartMenu.ts стартовое меню (DOM) с выбором уровня
└── engine/
└── GameLoop.ts игровой цикл с фиксированным шагом (60 Гц)
tests/ юнит-тесты ядра (bun test)
docs/ARCHITECTURE.md архитектура и потоки данных
CLAUDE.md правила для ИИ-агентов и разработчика
docs/HOWTO.md рецепты: как добавить врага/оружие/комнату