Привет. Я делаю ГИГАХРУЩ — браузерный survival horror / ARPG shooter про вылазки внутри безграничной бетонной структуры.
Да, звучит как питч из папки после этого меня точно забанят, поэтому начну с технической части. Это не Unity WebGL, не Phaser, не Godot export, не React‑обвязка вокруг canvas и не набор купленных ассетов. Игра собрана как один браузерный билд на TypeScript/Vite, WebGL/canvas, процедурных текстурах, процедурных спрайтах, процедурном звуке и плоских структурах данных.
Идея была простая и неприятная: сделать не красивую демку на три комнаты, а живой survival loop, где игрок готовит еду, воду, патроны и документы, уходит в вылазку, встречает NPC, монстров, фракции, торговлю, квесты и самосбор, а потом возвращается не в абстрактный хаб, а в мир, который помнит последствия.
В этой статье не будет «мы сделали революционный продукт, поставьте звезду». Будет другое: как маленькая браузерная игра постепенно превратилась в инженерный мешок с WebGL‑рейкастером, A‑Life, процедурной генерацией, локальными сохранениями, самодельным HUD и миллиардами токенов черновиков, проверок, правок и выброшенных вариантов.
Почему браузер
Потому что установка убивает импульс. Человек увидел странную игру про самосбор, нажал ссылку, загрузил страницу, умер в коридоре. Идеальный сценарий.
Браузер при этом сразу ставит рамки:
-
нельзя рассчитывать на тяжелый runtime;
-
нельзя прятать долгую загрузку за лаунчером;
-
нельзя раздать полгига ассетов и надеяться, что игрок терпелив;
-
нельзя забыть про pointer lock, fullscreen, mobile viewport, iframe-хосты и localStorage;
-
нельзя делать вид, что WebGL/canvas сами решат UX.
Поэтому базовое правило проекта стало таким: ноль runtime‑зависимостей, один браузерный билд, максимум данных и поведения из кода.
Это сильно отрезвляет. Если у тебя нет папки с ассетами, то текстуры должны родиться процедурно. Если нет нормального 3D‑движка, то камера и мир должны быть достаточно простыми, чтобы держаться на raycasting и фейках. Если нет ECS‑библиотеки, то сущности должны быть плоскими объектами, а мир — typed arrays и маленькие регистры.
Мир как данные, а не сцена
Главная ошибка, которую хотелось не повторять: делать «уровень» как коллекцию красивых объектов. Для хоррора это приятно, но для survival loop быстро становится мертвым декором.
В ГИГАХРУЩЕ мир описывается как клеточная поверхность с комнатами, коридорами, дверями, признаками, текстурами, контейнерами, сущностями и событиями. Рендер читает состояние, системы меняют состояние, генераторы строят состояние. Никакая картинка не должна владеть геймплеем.
Пример разделения:
-
coreхранит примитивные формы и World; -
dataхранит определения предметов, оружия, фракций, квестов, монстров; -
genстроит этажи, POI, комнаты, маршруты и начальное размещение; -
systemsобновляют AI, бой, квесты, экономику, самосбор, сохранение; -
renderтолько рисует.
Звучит скучно, но это как раз та скука, которая спасает игру от превращения в кашу. Когда появляется новый странный этаж, монстр или терминал, он не должен лезть в главный цикл и говорить: «Я особенный, вызовите меня вручную из main.ts». Он должен лечь в существующий контракт.
Рейкастер вместо честного 3D
Честный 3D был бы красивее. Еще он был бы дороже, тяжелее, дольше и потребовал бы другой pipeline.
Для ГИГАХРУЩА важнее не геометрическая честность, а решение игрока:
-
вижу ли я коридор;
-
понимаю ли я, где опасность;
-
могу ли я оценить дверь, цель, NPC, укрытие;
-
успеваю ли я испугаться до того, как меня съели.
Поэтому используется WebGL raycasting с процедурными поверхностями, спрайтами и canvas HUD. Картинка не пытается конкурировать с AAA. Она делает другое: быстро показывает бетонный лабиринт, дистанции, туман, вспышки, монстров, метки, кровь, интерфейс и события.
Самая полезная мысль тут: фейк нормален, если он рождает то же игровое решение.
Если игрок обходит темный проем, потому что там слышен чужой шаг, ему не важно, сколько полигонов в этом проеме. Ему важно, что решение было понятным и страшным.
Процедурные ассеты как дисциплина
Когда ассетов нет, исчезает соблазн решить проблему картинкой из интернета. Это больно, но удобно.
Текстуры стен, пола, следы, пятна, шум, спрайты монстров, многие визуальные пакеты и звуковые события генерируются из кода. Плохо сгенерированная картинка выглядит бедно, зато хорошая процедурная картинка умеет быть системной:
-
ее можно привязать к типу комнаты;
-
ее можно менять после самосбора;
-
ее можно использовать как след события;
-
ее можно сделать дешевой для билда;
-
ее можно воспроизводить по seed.
Да, иногда это выглядит грубо. Зато грубость честная: она не маскирует пустоту высоким разрешением.
A-Life без театра одного игрока
Я не хотел делать мир, где NPC появляются из воздуха рядом с игроком, а потом исчезают, когда он отвернулся. Поэтому A‑Life устроена как компактный слой идентичностей.
В начале новой игры создается большой пул процедурных жителей. На активном этаже материализуется только нужная часть: живые NPC, их инвентарь, отношения, фракции, занятия, смерть, память о событиях. Остальные остаются компактными записями, а не симулируются покадрово в фоне.
Это компромисс между «все честно симулируем всегда» и «все вокруг игрока — декорация». Полная симуляция всего мира была бы дорогой и бесполезной. Полная декорация убила бы ощущение жизни.
Ключевые правила:
-
обычные NPC не восполняются бесконечным спавнером;
-
смерть остается фактом;
-
фракционные и экономические события могут оставить след;
-
текущий этаж живет полноценно, остальные хранят компактное состояние;
-
игрок участвует в тех же социальных числах, что и NPC.
Когда игра начинает помнить, кого ты убил, кому помог, где украл и кто после этого перестал торговать, даже грубый интерфейс внезапно получает вес.
Самосбор как мутация мира, а не эффект на экране
Самосбор — центральная угроза. Его легко было сделать как красивую заставку: включить сирену, наложить красный фильтр, заспавнить монстра, снять HP.
Но тогда это был бы просто погодный эффект.
В текущей модели самосбор — локальная мутация мира: предупреждение, герметизация, проверка укрытий, давление, монстры, последствия, перестройка части пространства и события, которые потом остаются в состоянии этажа.
Это важно для ощущения: игрок не пережил «ивент», он пережил изменение места. До него комната была маршрутом, после него стала проблемой. До него дверь была проходом, после него стала границей. До него NPC был торговцем, после него может стать записью в памяти мира.
Почему не «ИИ написал игру»
Потому что это плохая история и плохая инженерия.
LLM в проекте используется много. Очень много. На уровне «если посчитать все черновики, ревью, планы, проверки, переписывания и выброшенные варианты, счет ушел в миллиарды токенов». Это смешно звучит, и, наверное, именно эта фраза гарантированно разозлит часть людей.
Но важная деталь: токены не компилируются.
Компилируется TypeScript. Работает WebGL. Падает typecheck. Ломаются тесты. Не сходятся контракты. Генератор может закрыть комнату. Сохранение может забыть состояние. HUD может стать нечитаемым. Игрок может не понять, что делать в первые две минуты.
LLM здесь не «автор игры», а шумный ускоритель итераций, черновиков и ревью. Он хорошо производит варианты и плохо несет ответственность. Ответственность остается в коде, тестах, локальных правилах проекта и ручной проверке.
Самый неприятный урок: нейросетью легко нагенерировать контент, но трудно сохранить архитектурный вкус. Поэтому у проекта жесткие внутренние правила:
-
не добавлять новый runtime без причины;
-
не тащить геймплей в рендер;
-
не расширять enum под каждый красивый термин;
-
не делать refill NPC, который стирает последствия;
-
не писать новый системный слой ради одного POI;
-
не обещать в README то, чего нет в билде.
Именно эти скучные ограничения важнее любого «вау, AI».
Что уже есть в текущем билде
Сейчас это не финальная игра, но уже не прототип с одной кнопкой. В браузерном билде есть:
-
подготовка к вылазкам: еда, вода, патроны, медицина, документы;
-
бой, оружие, PSI и монстры;
-
процедурные и авторские этажи;
-
фракции, торговля, экономика и караваны;
-
сюжетные и побочные задания;
-
A‑Life NPC с перманентными смертями;
-
самосбор с предупреждениями, укрытиями и последствиями;
-
localStorage‑сохранение;
-
canvas HUD, карта, лог сообщений, настройки интерфейса;
-
опциональная НЕТ‑СФЕРА через Cloudflare Worker/D1, если включить онлайн‑контур.
Отдельно смешно, что самая тяжелая работа оказалась не в «сделать монстра», а в «сделать так, чтобы игрок понял, что сейчас вообще можно делать».
Что болит
Первый запуск. Интерфейс. Читаемость. Темп вылазки. Плотность текста. Баланс между «я ничего не понимаю» и «я хочу разобраться».
Системы уже умеют больше, чем новый игрок способен принять за первые десять минут. Это типичная болезнь игры, которая долго росла изнутри: разработчик видит связи, игрок видит шум.
Поэтому сейчас приоритет не в том, чтобы добавить еще двадцать монстров. Приоритет в том, чтобы один живой путь был понятен:
-
проснулся в жилой зоне;
-
взял еду, воду, патроны;
-
понял ближайшую зацепку;
-
вышел в вылазку;
-
получил опасность;
-
принял решение;
-
вернулся или умер с понятной причиной.
Когда этот путь работает, поверх него можно строить странность. Когда он не работает, вся процедурность превращается в дым.
Зачем я это тащу на Хабр
Потому что мне интересна не только реакция «нравится / не нравится игра», а техническая проверка: где такая архитектура выглядит разумной, а где я сам себе построил бетонный гроб.
Мне особенно интересны три темы:
-
насколько оправдана ставка на zero-runtime browser build для игры такого типа;
-
где лучше проводить границу между симуляцией и кинематографическим фейком;
-
как не дать LLM-ускоренной разработке распухнуть в набор красивых, но несвязанных систем.
Если хочется просто посмотреть, что это за странность, игра запускается в браузере:
Игра ГИГАХРУЩ (запустится в браузере)
А если хочется ругать — лучше ругать конкретно: первый запуск, HUD, WebGL‑картинку, A‑Life, procedural generation, самосбор или саму идею survival horror в браузере без движка.
ГИГАХРУЩ все равно уже существует. Теперь вопрос в том, получится ли сделать из этой бетонной массы игру, в которую человек не только зайдет из любопытства, но и вернется после первой смерти.
ссылка на оригинал статьи https://habr.com/ru/articles/1043232/