Newer
Older
rpg / docs / plan.md

План развития и актуальные задачи

Живой документ планирования: сюда сходятся планы на развитие, актуальные задачи и проработка крупных направлений. Срез-статус архитектуры — docs/demo.md (дорожная карта там — историческая, актуальный план здесь).

Дата ревизии: 2026-09-07.

Статус проекта (2026-09-06): техно-демка движка. Основные силы — движок (packages/engine); игра — витрина и полигон проверки API. Приоритет решений: что двигает движок (API, тулзы, доки, границы), то и делаем; игрового контента ровно столько, сколько нужно демонстрации.


Актуальные задачи

# Задача Статус
1 Срез «меньше ошибок»: реестры ID, pre-commit, разрезание LocationScene, фикстуры, fail-fast waitFor ✅ сделано (c379f20, 16b59d8, 39c6349)
2 AI-генерация текстур и спрайтов (работа B, ниже) B0+B1 ✅ (PoC); B3 проба ✅ (SD-атласы, 6.6 мин/вид); B2 отложено — RD API или ручной арт
3 AI-генерация аудио (работа A, ниже) 📋 спланировано, отложено
4 Акт 2: новые локации/сюжет по docs/world.md очередь после акта 1+AI-ассетов
5 Замена сгенерированных плейсхолдеров арта на AI/ручной арт в составе работы B
6 Крупные объекты: footprint в движке, слоты арта (работа C, ниже) в работе
7 Возможности аудио-движка (работа D, ниже): sfx-хендл, полифония, наблюдаемость, буферы ✅ D0–D2 сделаны (2026-09-07)

Отложено: IsoLayout как параметр игрыDEFAULT_ISO в math/iso.ts остаётся единственной точкой входа; прокидывание конфига игры через ~15 мест движка не даёт пользы демо и добавляет второй способ рассинхрона изометрии.

Приоритет между работами A и B: B (изображения) выше — визуальный стиль блокирует восприятие акта 2; аудио сейчас закрывается процедурным генератором (tools/audio/gen.mjs) приемлемо.


Ограничения (читать первым)

  • Машина разработки: Intel HD 620 (iGPU, нет CUDA), 15 ГБ RAM, 4 ядра CPU. Только CPU-инференс (подтверждено пробой ускорителей, см. B3). Модели класса SDXL/FLUX/SANA/DreamLite отпадают либо как «медленный офлайн-пакет» (десятки минут на картинку). Целевой класс — компактные модели (< 1.5B параметров), CPU-рантаймы; главный бесплатный рычаг скорости — меньше шагов диффузии, а не квантизация и не iGPU.
  • Стиль игры жёсткий: палитра 32 цветов (tools/pixelart/palette.mjs), размеры спрайтов по docs/art-style.md, pixel-perfect. Любая AI-генерация — только как сырьё с обязательной пост-обработкой: даунскейл nearest, квантизация в палитру, проверка чек-листом арт-библии. AI-вывод не попадает в assets/ напрямую.
  • Формат аудио фиксирован: моно 22050 Гц, 16-бит WAV (tools/audio/gen.mjs). AI-вывод приводится к нему (ffmpeg: sample rate, моно, нормализация, обрезка тишины).
  • Лицензии весов: для игры важен коммерчески-допустимый статус. Отмечено в таблицах; некоммерческие веса (CC BY-NC) — только для экспериментов/PoC.
  • Детерминизм: у всего пайплайна фиксированный seed в конфиге генерации — регенерация не должна молча менять ассеты (аналогично npm run maps:fresh).

Работа B — AI-генерация текстур и спрайтов

Классы потребностей

  1. Тайлы (трава, пепел, вода…) — процедурный генератор уже даёт приемлемый результат; AI ценен для сложных поверхностей (бутеи, руины, интерьеры).
  2. Спрайты объектов (предметы, декор, интерактивы) — главная точка роста: сейчас Graphics-плейсхолдеры.
  3. Спрайты персонажей + атласы (герой, NPC, враги, кадры анимаций) — самое сложное: консистентность кадров, фиксированные размеры листа (hero_sheet.png — контракт арт-библии).

Кандидаты

Модель Размер Железо Нативная палитра Лицензия Комментарий
PXG-Tiny (HF: Tarul/pxg-tiny) 483K CPU, NumPy, 1.8 МБ да (прямые индексы) MIT + CC0 16×16, 38 классов. Идеален по железу, но узкий домен
PixelGPT-24×24 (github.com/unstonio/pixelgpt-24x24) 68M CPU, ~22 с да, 5 цветов/спрайт, кастомная палитра на запрос нет (не указана) 24×24; отказов нет, домен тянет частично (см. B1). Веса в репо; датасет 20K — CC BY 4.0
Pixel Forge (cochranblock) 1.1–17M CPU (Rust) да, 7 встроенных палитр Unlicense 108 классов объектов; появилась фича 4-directional sprite sheet relight — кандидат пробы B3 (нужен Rust-тулчейн)
SD_PixelArt_SpriteSheet_Generator (Onodofthenorth) ~1B (SD 1.5) CPU 6.6 мин/вид fp32 (25 шагов — 11 мин; q8 отвергнуто: медленнее и шумит) нет (пост-обработка) Apache-2.0 4 ракурса по токенам (FSS/RSS/BSS/LSS); кадры — позы стоя, не walk-цикл. Проба B3 ✅ — рабочий путь для разовых атласов
Retro Diffusion SD1.5 (LostMedia, архив) ~1B CPU минуты/картинку нет (пост-обработка) Public Domain классика пиксель-диффузии; для офлайн-пакета
Retro Diffusion API (RD Plus/Tile/Animation) облако да платный API лучший результат для тайлов/анимаций; фолбэк, если локальное не тянет
LPC-style (PIXEL-T2I и др.) research GPU нет research перспективное направление для атласов 4 ракурса × walk/slash

Вывод по классам (после B0+B1): инвентарь/декор — PXG-Tiny локально (её классы); простые объекты 24×24 — PixelGPT (но лицензии нет — только PoC); критичные интерактивы и тайлы сложных поверхностей — RD API (платный) или ручной арт; дообучение под игру не делаем. Персонажи-атласы — кандидаты пробы: SD_PixelArt_SpriteSheet_Generator (Apache-2.0, CPU-минуты) и Pixel Forge relight (нужен Rust); фолбэк — платный RD API или ручной арт. Отдельный путь для полноразмерных атласов с боевыми кадрами — LoRA к Qwen-Image-Edit (Apache-2.0), но база ~20B: только разовая генерация на Kaggle/Colab GPU, результат — в наш пайплайн пост-обработки.

Пайплайн интеграции (проект решения)

tools/aiart/gen.mjs        # вызов модели (seed, промпт из манифеста)
  → tools/aiart/post.mjs   # даунскейл nearest → квантизация palette.mjs → дедуп
  → tools/aiart/manifest.json  # список ассетов: промпт, seed, размер, статус
  → apps/game/assets/…     # только после ручного апрува (review-каталог)

Принципы: манифест-драйвен (как maps/); апрув-гейт (человек смотрит обзорный лист перед попаданием в игру); ревизия в git; проверка стиля — чек-лист docs/art-style.md + скриншот-смоук.

Инструменты, которых не хватает (по итогам B0–B3)

  1. sheet2atlas — сборщик атласа из AI-листов (главная дыра). SD-лист 512² → кроп фигур (bbox, отсев фона) → нормализация в слоты 16×24/32×48 → раскладка в сетку hero_sheet.png + hero_sheet.json (контракт арт-библии). ✅ Сделан (2026-09-06): tools/aiart/atlas.mjs (gen/build/promote) + atlas-manifest.json + sd_sheet.py; движковая база — findFigures/ resizeRect/buildAtlas в @rpg/engine/tools. Палитра — параметр манифеста (game или palettes/<name>.json на 64/128/256 цветов). Фон листов модели неоднородный + сплошная «земля» под фигурами — автодетект фигур не срабатывает, в манифесте работают crop-оверрайды (раскладка 4 фигуры в ряд стабильна).
  2. Палитровый ремапер (recolor): перекраска готового квантованного спрайта маппингом цветов палитры. Две потребности: сгладить «плавающие» промпт-цвета SD (приводить плащ к каноническому) и дешёвые цветовые вариации NPC из одного базового спрайта. ✅ Сделан (2026-09-06): tools/aiart/recolor.mjs (CLI по ключам палитры/hex) + поле remap в манифесте атласов — применяется в build после квантизации (плащ звонаря приведён к C0/C1).
  3. Линтер арта (авто-чеклист арт-библии): скрипт-гейт перед попаданием в assets/ — размер в слоте, все цвета из палитры, детект «мыла» (градиентные пары соседних пикселей — чужая плотность пикселя). ✅ Сделан (2026-09-06): tools/aiart/lint-art.mjs (npm run art:lint по всем assets, негативы проверены); в agent:check не заведён — по мере надобности.
  4. Отложено: клиент RD API (tile/animation) — только если решимся платить (B2, кадры walk-цикла); генерация/склейка walk-цикла из поз — пока ручной арт, инструмента не видно.

Этапы

  • B0 (PoC, ~1 вечер): запустить PXG-Tiny/Pixel Forge локально на CPU; сгенерировать 10–20 объектов, прогнать пост-обработку, сравнить с текущими плейсхолдерами. Критерий: «хотя бы 30% годных без ручной правки». ✅ Выполнен (2026-09-06): PXG-Tiny на CPU (~6 с/спрайт), 20 спрайтов, 40% годных, стиль совпал с игрой на 100%. Пайплайн: tools/aiart/ (post.mjs — кроп/квантизация в палитру + обзорный лист; manifest.json — вердикты). Pixel Forge отложен (нет Rust-тулчейна). Ограничение: критичные для игры ассеты (колодец, столб, рычаг, колокольчик, моты) вне 38 классов модели — для них дообучение / RD API / ручной арт.
  • B1 (домен, вторая модель): PixelGPT-24×24 на доменных интерактивах (промпты + обусловливание палитрой игры из 5 цветов). ✅ Выполнен (2026-09-06): 18 спрайтов, 44% годных, отказов нет — доменные объекты (колокол, дверь, камин, столб, моты) модель рисует, где PXG-Tiny отказывала. Ограничения: даунскейл 24→16 губит деталь (колодец good на 24×24), фон часто залит, ровно 5 цветов, ~22 с/спрайт CPU, лицензии на код/веса нет — в игру нельзя. Манифест: manifest-b1.json.
  • B2: тайлы сложных поверхностей (img-условность от существующих тайлов) — локальным моделям недоступно, кандидат RD API; отложено.
  • B3 (проба, 2026-09-06): SD_PixelArt_SpriteSheet_Generator на CPU (venv-pxgpt, fp32). Токен-ракурс работает: 4 фигуры читаются; но кадры — вариации позы стоя (не walk-цикл), промпт-цвета плавают, кадры ~120 px (даунскейл до 16×24 некратный). Тайминги: 25 шагов — 11 мин, 15 шагов — 6.6 мин (взято за рабочий режим). Квантование q8_0 (stable-diffusion.cpp, GGUF) отвергнуто: 34 мин (ggml-ядра int8 без VNNI медленнее fp32-oneDNN) и VAE в q8 даёт шум — probe-b3/sd_q8_fss_42_broken.png. Вердикт: путь рабочий для разовых атласов (4 вида ≈ 30 мин/персонажа), но кадры-позы придётся дорабатывать руками; полный прогон — при потребности акта 2. Пробы: apps/game/tools/aiart/probe-b3/. Фолбэк — RD API или ручной арт.
  • B3-доп (ускорители, 2026-09-06): альтернативные пути разгона проверены и отвергнуты, остаёмся на fp32-CPU (diffusers, 4 потока):
    • iGPU HD 620 (Vulkan/ggml) — не готовился к прогону осознанно: стек Vulkan в системе есть (Mesa ANV Gen9.5, glslc), но HD 620 — 24 EU и общая с CPU память ~30 ГБ/с, т.е. на порядок слабее CPU в матмулах; ggml-Vulkan на Gen9.5 обычно даёт 10–25 мин на SD1.5 512²×20 — сравнимо или хуже. OpenCL мёртв: intel-compute-runtime 26.x — только Tiger Lake+ (Gen9.5 — legacy-ветки). Оставлено как есть, без бенчмарка.
    • Квантование q8_0/q4 — отвергнуто ранее: на 7-м поколении без VNNI ggml-ядра int8 медленнее fp32-oneDNN (34 мин против 11), VAE в q8 шумит.
    • Меньше шагов — единственный рабочий рычаг: 25→15 шагов даёт 11→6.6 мин без видимой деградации кадра; ниже 15 качество токен-ракурса падает.

Работа C — крупные объекты (footprint + большие спрайты)

Акт 2 захочет здания и крупные деревья — объекты больше 1×1 тайла. Сегодня движок умеет только TallSpec (1 тайл footprint + произвольная высота) и ручной blocked. Большой спрайт, якоренный в один тайл, сортируется глубиной по точке — герой сбоку от дома перекрывается неверно.

Что нужно

  1. Движок: footprint w×h — коллизия по всему прямоугольнику, земля под ним, спрайт якорем низ-центр footprint'а; глубина по прямоугольнику ((x+w-1)+(y+h-1), IsoDepthLayer.addRect), а не по точке якоря.
  2. Арт-библия: слоты крупных спрайтов — фиксированные размеры с якорями (дом 3×3, большое здание 4×4…), чтобы любой источник рисовал в готовый слот.
  3. Арт: три пути — крупный объект кодом в gen.mjs (композит: модули стен + крыша — наш бесплатный путь); апскейл nearest из 24×24 (только болванка — чужая плотность пикселя рядом со спрайтами 1×); RD API (умеет большие размеры и тайлы, платный).

Этапы

  • C0 (движок) ✅: props в TileMapData (footprint, коллизия по всему прямоугольнику, земля под ним), IsoDepthLayer.addRect (глубина по диагонали юго-восточного угла footprint'а), валидация в mapFormat, тесты; LocationScene вставляет map.propViews в общий depth-слой.
  • C1 (арт-библия) ✅: слоты крупных спрайтов в docs/art-style.md (дом 2×2 — 64×80, дом 3×3 — 96×96, здание 4×4 — 128×112; якорь ставит движок). Плотность пикселя — как у тайлов; AI-апскейл в слоты не попадает.
  • C2 (проба) ✅: большой дом 2×2 кодом в gen.mjs (tiles/house_big.png, 64×80, композит: модули щитов + крыша шпал + козырёк + окна) против апскейл-болванок 24→48 из B1 (apps/game/tools/aiart/probe-c2.png). Вывод: для крупных объектов — код-композит в gen.mjs; апскейл даёт мыло с чужой плотностью пикселя и залитым фоном (только черновая болванка), нативно больших размеров локальные модели не умеют. RD API остаётся опцией, если код-композита не хватит. Неквадратные footprint'ы (2×1, 3×1, 4×2): движок умеет (props w×h; поверхности заполняются обычными тайлами 1×1); AI-генерация — только квадраты (неквадрат собираем из 1×1 на уровне карты), код-композит — любой размер, RD API Tile — нативно прямоугольные.

Работа A — AI-генерация аудио

Классы потребностей (по пользовательскому сценарию)

Класс Что это сейчас AI-кандидат Железо
Окружение (ветер, пепел, вода прудов) процедурный шум в gen.mjs Stable Audio 3 Small-SFX (433M, CPU, 120 с) — длинные лупы; луповальность через crossfade-склейку CPU ок
SFX взаимодействия (шаги, клик, удар, звон) gen.mjs, приемлемо Stable Audio 3 Small-SFX (тот же рантайм; seed-детерминизм для вариантов) CPU ок (~секунды-десятки секунд на клип на 4 ядрах)
Музыка: фоновые лупы gen.mjs (треки 3 областей) Stable Audio 3 Small-Music (433M, CPU, 120 с) — короткие лупы; либо ACE-Step 1.5 2B turbo INT8 (CPU-медленно: минуты-десятки минут на трек, но офлайн-пакет) Small-Music — да; ACE-Step — терпимо для пакета
Музыка: катсцены/сюжетные моменты нет (трек + звон) ACE-Step 1.5 — полноценные треки с настроением/структурой, стемы; MusicGen small — фолбэк для мелодических заготовок офлайн-пакет, не hot-reload

Кандидаты (сводно)

Модель Размер VRAM/железо Длина Лицензия Роль у нас
Stable Audio 3 Small-SFX / Small-Music 433M CPU (TFLite), ~1.9 ГБ пик 120 с веса: Stability Community License; код MIT основной локальный рантайм для SFX + лупов
ACE-Step 1.5 2B (turbo INT8) CPU (медленно), GPU <4 ГБ 10 с–10 мин, стемы MIT музыка катсцен/сюжета, офлайн-пакет
MusicGen small (AudioCraft) 300M CPU ~4 ГБ RAM ~30 с MIT/CC-BY-NC веса фолбэк, мелодия-условность
Stable Audio Open 1.0 1.2B GPU ~2.5–8 ГБ 47 с Stability Community зрелый, но на нашей машине безнадёжно медленный; пропускаем

Пайплайн интеграции (проект решения)

tools/aiaudio/gen.mjs       # вызов модели, seed, промпт из манифеста (аналог aiart)
  → post: ffmpeg → 22050 моно 16-bit → нормализация → crossfade-луп для ambience/sfx
  → review-каталог → apps/game/assets/audio/{sfx,ambience}/*.wav

Принципы те же: манифест, апрув-гейт, seed-детерминизм, формат игры не меняется (шины master/music/sfx/ambience в движке уже готовы). Лупы проверять скриптом (стык начала/конца без щелчка).

Этапы

  • A0 (PoC): Stable Audio 3 Small-SFX локально на CPU; сгенерировать 5 SFX-замен (step, ui_click, bell_hit) + 1 амбиент-луп прудов. Критерий: звук лучше процедурного на слух и формат сходится.
  • A1: пайплайн aiaudio + манифест; замена SFX, амбиент-лупы областей.
  • A2: музыкальные лупы (Small-Music), сравнение с gen.mjs-треками.
  • A3: ACE-Step офлайн-пакет для катсцен акта 2 (1–2 трека под моменты).

Работа D — возможности аудио-движка

Итог аудио-работ (2026-09, коммиты 57bce47…4c1c56c): в движке — 4 шины, кроссфейд слотов music/ambience, playLoop без слота, pan/rate, шпион onPlayed; в игре — позиционный AudioSystem, локальные амбиент-слои, событийные звуки боя, DEV-лог __gameAudioLog. Ниже — потребности, которые упёрлись в границы AudioManager, по убыванию полезности. Игровая логика (кто слушатель, затухание по дистанции, playAt) остаётся в игре — в движок её не тащить.

Потребности

  1. Управление играющим разовым звуком. play() возвращает void: нельзя остановить, перезапустить «с нуля» (опция «убить прежний экземпляр ключа») или изменить volume/pan/rate в полёте. Самый чувствительный кейс — движущийся источник: панорама фиксируется в момент запуска.
  2. Лимит полифонии в движке. Число одновременных источников ничем не ограничено — игру спасает только MIN_INTERVAL на ключ в игровом AudioSystem. Нужен maxVoices с воровством самых тихих/старых голосов — защита от каскада (десяток combat:* в один тик).
  3. Шпион на все запуски + окончание. onPlayed зовётся только для sfx — лупы (музыка/амбиент/слои) шпион не видит, игре пришлось логировать амбиент вручную в Game.playAmbience. Нет onEnded — нечем ловить «звук доиграл» для синхронизации с анимацией.
  4. Длительность буфера наружу. duration(key) — сейчас её не достать, а нужна катсценам и генератору шагов (не играть следующий шаг раньше конца предыдущего).
  5. Играть буфер из памяти. playBuffer(AudioBuffer) — синтез сейчас только оффлайн (tools/wav.mjs); генерировать вариации звука в рантайме движок не может (сейчас джиттер имитируется rate).

Этапы

  • D0 (движок): sfx-хендл + полифония. SfxHandle { stop(fadeSeconds?), setVolume(v), setPan(v), setRate(v) } — по образцу MusicHandle; опция restart/«один экземпляр на ключ»; maxVoices с воровством голосов.
  • D1 (движок): наблюдаемость. onPlayed на все запуски (sfx + лупы, опции нормализованы); onEnded(key); duration(key). Игра: ручное логирование амбиента убрано (лог целиком из шпиона).
  • D2 (движок + игра): буферы из памяти. playBuffer(key, buffer, opts)
    • createBuffer(data); примитивы синтеза вынесены в чистый @rpg/engine/tools/synth.mjs (без node-импортов — wav.mjs в браузере не соберётся); игра — systems/StepVariants.ts: 3 процедурных варианта шага на поверхность (сид ~253–256 + сдвиг, полосы как в gen.mjs), до unlock — файловый шаг. Гвард: @rpg/engine/tools/* — публичное API.

Дальше (после D — закрываем «по инструментарию»)

  • Инфраструктура: mute/suspend при visibilitychange (свернул таб — тишина); bus в опциях разового play; exponential-фейд (линейный на громких затуханиях слышен как «ступенька»).
  • Музыкальный слой: плейлист/секвенция тем («тема лугов → тема боя → назад»), стем-миксинг — параллельные лупы-слои одной темы с независимой громкостью (спокойно/настороженно/бой; ложится на существующий playLoop). Контент закрывается инструментарием Работы A (этапы A2–A3), API — здесь.

Открытые решения (принять перед стартом работ)

  1. B0: какая из GPT-пиксель-моделей заходит лучшезакрыто B0+B1: PXG-Tiny — инвентарь/декор, PixelGPT-24×24 — домен частично, но лицензии нет.
  2. Персонажи-атласы: дообучение локально vs RD API vs ручной арт — дообучение под игру отвергнуто; осталось: платный RD API vs ручной арт.
  3. Python-окружениезакрыто: venv вне репо (~/.cache/rpg-ai/venv, venv-pxgpt), веса в ~/.cache/rpg-ai/; в git — манифесты и review-PNG.
  4. Порог апрува: кто смотрит review-лист (пользователь) и где фиксируется вердикт (пометка в манифесте).

Что НЕ делаем

  • Облачные API в основном пайплайне (только как опциональный фолбэк для спрайтов).
  • Модели с некоммерческими весами в основном пайплайне (DreamLite CC BY-NC — только эксперименты); веса без лицензии (PixelGPT) — то же.
  • Дообучение моделей под конкретную игру.
  • TTS-голоса персонажей — вне среза, кандидат на будущее: Kokoro-82M (CPU).