ТЗ на реализацию экранов подготовки и осмотра. Дизайн решён и лежит в Modes - Preparation Screens; чертежи — раздел Лаборатории ui-prep-final (./scripts/lab-serve.ps1 ui-prep-final). Здесь — что для этого нужно в коде, чего сейчас нет и в каком порядке делать.

Написано до первой строки кода по требованию Макса (22.08.2026): «Сначала ЗАПИШЕМ ВСЕ ТЗ по нашим вайрфреймам, изучив что и как у нас уже UI, убедимся что все решили, ничего не забыли обговорить и лишь потом по тз все выполняем».


1. Что строим

Семь экранов, принятых 22.08.2026:

ЭкранЖест открытия
1Страница «Отряд» — четвёрка телами, лента из 8 мествкладка экрана подготовки
2Страница «Предметы» — «Сосуд» строкой, 3+1 слот, складвкладка того же экрана
3Панель осмотра — колонка у правой кромкиЛКМ по юниту, везде где есть юнит
4Карточка «Сосуда», таб «Основное» — разворот, 4 клеткиПКМ по «Сосуду»
5Карточка «Сосуда», таб «Дополнительно» — лор и статистикатаб внутри карточки
6Карточка Реликвии, таб «Основное» — кит и 6 улучшенийПКМ по Реликвии, кнопка «о Реликвии»
7Карточка Реликвии, таб «Дополнительно» — лор и статистикатаб внутри карточки

Сквозное правило, определяющее плотность всех семи: описания живут в тултипах, на поверхности имена (§0 дизайн-дока). Исключения — числа статов и цена способности.


2. Что уже есть (и переиспользуется как есть)

Инвентарь снят с HEAD 22.08.2026. Это не справочник — список того, что не надо писать заново.

СлойЧто естьГде
НавигацияUiNavigator, UiScreen, ScreenKind, MenuRouter.OpenLoadout(OpenLoadoutRequest)Scripts/UI/Navigation, MenuRouter.cs
ТултипыTooltipSystem, TooltipChain (лимит 3, FIFO), TooltipManipulator, ITooltipContentFactory, KeywordLinksScripts/UI/Tooltips
КомпонентыSlot (три размера, SetSelected, SetIcon), Chip, SlantedChip, PlateButton, PanelFrame, SlantedPanel, BackButton, RelicCard, TooltipCard, AspectBoxScripts/UI/Components
Реестр состоянийUiComponentRegistry + гейт UiStateGateTests + контактный листтам же
Экран лоадаутаLoadoutViewModel, LoadoutInventoryView, LoadoutScreen.uxml, LoadoutInventoryScreen.uxmlScripts/UI, UI/Screens
Состояние забегаRunState.Guild: RosterSlot[], RosterSlot { VesselId, RelicId, AiPresetId, VesselItemIds, SavedPosition, Injuries }Scripts/Guild/RunState.cs
ЧеловекVesselState { Id, BirthSeed, Name, PregenId, PositiveTraitId, NegativeTraitId, RunsSurvived }Scripts/Guild/VesselState.cs
ТравмыInjuryLedger (SlotsOf, Inflict, AdvanceNode, Remove), InjuryCascade, ConsequenceDataScripts/Guild
Память домаGuildBook — Летопись, Хроника, Мемориал; ChronicleEntryScripts/Guild/GuildBook.cs
Команды забегаIRunCommands: SetSlotPosition, SetSlotRelic, InflictInjury, HealInjury, AddGold, RequestSaveScripts/Guild/Commands
КонтентItemData (скоуп Vessel/Party, моды, активка, иконка), TraitData (полярность, моды), RelicData, VesselDataScripts/Data/Definitions
КонфигGameConfig.GuildSize (сейчас 4), VesselItemSlots (3), RelicCapacityBase/MaxGameConfig.cs
Сборка бояGuildRoster.Build(run) — берёт весь run.Guild слот-в-слотScripts/Game/Flow/GuildRoster.cs
КоопIRunCommands у владельца, жест гостя — каналом (образец DeploymentIntentRelay)Scripts/Game/Session/Net

3. Чего нет — разрывы между дизайном и кодом

Это главный результат разведки: половина принятого дизайна не поддержана данными.

3.1. Отряд из восьми и боевая четвёрка

GameConfig.GuildSize = 4, а GuildRoster.Build отправляет в бой весь ростер. То есть понятия «кто выходит в бой» в коде нет вовсе: сейчас в бой идут все, кто есть.

Нужно:

  • GuildSize8 (данные, не хардкод), плюс сколько мест открыто на старте (6);
  • признак боевой четвёрки в RunStateразвилка, см. §9.1;
  • GuildRoster.Build берёт только боевых и в их порядке;
  • места 7–8 закрыты до улучшения — механики открытия тоже нет (§9.3).

Сейв. RunState помечен [SaveSchema(1)]; расширение массива и новое поле — изменение схемы. Старый сейв обязан читаться: восемь мест при четырёх записанных, боевые — первые четыре.

3.2. Команд состава и предметов не существует

В IRunCommands есть SetSlotRelic и SetSlotPosition, но нет ничего про людей и вещи. Нужны:

КомандаЧто делает
SetSlotInBattle(int slotIndex, bool inBattle)ставит «Сосуда» в бой или уводит в запас
SwapSlots(int a, int b)меняет местами два места ростера
SetSlotItem(int slotIndex, int itemSlot, string itemId)надевает предмет; пустой id — снимает
MoveItem(int fromSlot, int fromItemSlot, int toSlot, int toItemSlot)перекладывает вещь между людьми одним действием

Все — у владельца забега; гость публикует жест каналом и исполняет владелец (правило равенства, CLAUDE.md §Кооп).

3.3. Улучшений Реликвии нет в данных

RelicData не знает про улучшения вовсе, а карточка показывает шесть (3×T1 + 3×T2) с состояниями «взято / доступно / закрыто». Нужны: тип улучшения (или поле в RelicData со списком), место взятых в RunState (на Реликвию, не на «Сосуда»), правило доступности по уровню Реликвии.

Дизайн улучшений — методичка; самих шестёрок для конкретных Реликвий тоже ещё нет.

3.4. Статистики «Сосуда» нет

Таб «Дополнительно» показывает шесть строк: боёв, побед, смертей, урона нанесено, урона принято, походов. В коде есть только VesselState.RunsSurvived и Летопись (ChronicleEntry — подвиги, а не счётчики). Нужен либо счётчик на VesselState, либо агрегат по Летописи — §9.4.

3.4a. Людей в забеге нет вовсе — и дом их не заводит

Найдено при проводке экрана 22.08.2026. RosterSlot.VesselId пуст у всех: наём не написан, а ProfileService.CreateGuild заводит дом с пустым Roster. То есть страница «Отряд», подключённая к живому забегу, покажет восемь свободных мест — показывать некого.

Сделано: VesselFactory рождает человека из сида (имя и перки), пул имён вынесен в ассет VesselNamePool (журнал — про соседнее решение; сама фабрика описана в своём докстринге).

Осталось и требует нового шва: люди принадлежат ДОМУ (GuildState.Roster), а забег ссылается на них строковым id. Дом грузит и пишет ProfileService (сборка Game), забег держит RunStateService (сборка Guild), и IProfileService живёт в Core — то есть отдать ростер через него нельзя, Core не видит GuildState. Нужен отдельный интерфейс уровня Guild (например IGuildRosterView) с реализацией в Game; без него связка «дом → забег» не пишется, а не пишется она — экран остаётся пустым.

Ассета пула имён ещё нет: тип создан, но Unity его не видел (Auto Refresh выключен). Ассет заводится после одного рефреша редактора.

3.5. Лор и внешность — процедурные, генератора в UI нет

VesselState.BirthSeed объявлен как источник досье и внешности («из него детерминированно разворачивается досье (мечта / характер / байка) и внешность»). Генератор досье для UI не найден — на карточке нужен текст «кто, откуда, как выглядит».

3.6. Облик в облачении Реликвии

Карточка показывает человека в текущем облачении. Это не UI-задача: нужен способ получить изображение связки «Сосуд + Реликвия» — рендер живого UnitView в текстуру либо собранный спрайт. Решения нет.

3.7. Склада предметов не было вовсе

Найдено при реализации фазы 0 и сразу закрыто: предметы «Сосуда» существовали только надетыми (RosterSlot.VesselItemIds), а снятая вещь исчезала из мира — хранить её было негде. Заведён RunState.ItemInventory, все правки идут одним глаголом SetSlotItem (журнал).

3.8. Перетаскивания в UI Toolkit у нас ещё не было

Обе страницы стоят на перетаскивании (в бой, в запас, местами, надеть, снять). Готового манипулятора в Scripts/UI/Components нет — это новый общий контрол, а не код экрана.


4. Экраны: контракты

Единый вход — экран подготовки с лентой страниц; страницы переключают режим работы с составом, четвёрка остаётся на месте.

4.1. Страница «Отряд»

  • Данные: RunState.Guild (8 мест), VesselState по VesselId, RelicData по RelicId.
  • Показывает: четыре тела на живой расстановке (арена под интерфейсом, вуаль лёгкая), подпись — имя и Реликвия; ленту из 8 мест внизу: занятые с портретом и меткой «в бою» / «в запасе», пустые пунктиром, закрытые под замком.
  • Жесты: ЛКМ — панель осмотра; ПКМ — карточка; тянуть — в бой, в запас, местами.
  • Состояния: пусто · занято · закрыто · выбрано · перетаскивается · недопустимая цель.
  • В тултипе: ничего сверх имени и Реликвии на самой странице нет — всё в панели и карточке.

4.2. Страница «Предметы»

  • Данные: те же плюс RosterSlot.VesselItemIds, ItemData, GameConfig.VesselItemSlots.
  • Показывает: четыре строки (портрет, имя, Реликвия, 4 квадратных слота: 3 открытых + закрытый), склад всех доступных предметов сеткой, панель осмотра справа.
  • Жесты: тянуть из склада в слот и обратно, между людьми; ЛКМ — панель; ПКМ — карточка.
  • В тултипе: что делает предмет (статы, триггер, заряды).

4.3. Панель осмотра

  • Живёт везде, где есть юнит — подготовка, бой, пауза, Двор, расстановка. Один контрол.
  • Данные: боевой стат-блок ИТОГОМ (IUnitStatPreview уже есть в LoadoutViewModel), перки, снаряжение, профиль AI.
  • Показывает: портрет, имя, Реликвия и класс; статы числами (не в тултипе!); перки чипами; снаряжение иконками; поведение чипом; две кнопки — «О Сосуде» и «о Реликвии».
  • Кнопка без Реликвии гаснет текстом, но остаётся живой (ui-feedback §1 — HARD).
  • Скролл обязателен: содержимое длиннее колонки.

4.4. Карточка «Сосуда» — разворот, два таба

  • Окно 86% кадра, кромка подложки видна, закрывается Esc / повторным ПКМ / кнопкой.
  • Таб «Основное»: облик в облачении колонкой слева; четыре клетки — статы, перки (чипы), снаряжение (иконки + переход к Реликвии), травмы (6 мест 3/2/1 + чипы названий + Закалка).
  • Таб «Дополнительно»: слева кто и откуда, как выглядит; справа шесть строк статистики и строка летописи.
  • В тултипе: перк, травма, предмет, Закалка.

4.5. Карточка Реликвии — тот же каркас

  • Таб «Основное»: знак и облачение, автоатака, уровень и копии, пассивки; справа три способности (знак, имя, цена) и под ними шесть улучшений рядами T1 / T2 с состояниями.
  • Таб «Дополнительно»: чей был, как меняет носителя, статистика Реликвии, список носителей.
  • В тултипе: эффект и условие способности, что даёт улучшение.

5. Что добавить в данные

КудаЧтоЗачем
GameConfigGuildSize = 8, GuildSlotsOpenAtStart = 6, BattleSlots = 4числа состава — данные, не хардкод
RunStateпризнак боевой четвёрки (§9.1), места взятых улучшений Реликвийбез них экран нечего показывать
IRunCommandsчетыре команды из §3.2правки состава и вещей идут одной дорогой
RelicDataсписок улучшений (6: 3×T1 + 3×T2)§3.3
VesselStateсчётчики статистики либо агрегат по Летописи (§9.4)таб «Дополнительно»
UI-компонентыDragManipulator, InspectPanel, SpreadCard (окно с табами), UpgradeGridновые общие контролы

Все новые компоненты обязаны попасть в UiComponentRegistry со своими состояниями — иначе гейт UiStateGateTests красный, и это правильно.


6. Кооп

Гильдия единая, «Сосуды» между игроками не распределяются. Отсюда:

  • страницы, панель и карточки — буквально один код у хозяина и гостя; разница считается дефектом;
  • осмотр — чтение: открывается любому, чужой осмотр не блокирует;
  • правки состава и вещей — жест публикуется одинаково у обеих ролей, исполняет владелец.

7. Локализация

Все надписи — ключами сразу, EN + RU (ui.* — интерфейс, ContentLocalization — контент). Тексты тултипов идут от контента ({id}.desc), надписи экранов — свои ключи. Правило проекта: дописывать потом дороже, чем закладывать сразу.


8. Порядок работ

ФазаЧтоПроверяется
0сделано 22.08.2026 — данные: восемь мест, InBattle, склад предметов, три команды14 тестов зелёные
1сделано 22.08.2026DragManipulator и DropZoneManipulatorкомпиляция; кадр — за фазой 2
2сделано 22.08.2026 — страница «Отряд»: разметка, вью, стили, проводка к забегу17 тестов; превью Alebardium → UI Preview → Party
3сделано 22.08.2026 — страница «Предметы»: строки, слоты 3+1, склад, проводка18 тестов; превью Alebardium → UI Preview → Items
4сделано 22.08.2026 — панель осмотра компонентом, тултипы на чипах, дом на обеих страницах12 тестов; кадр из игры — за подключением к навигации
5сделано 22.08.2026 — карточка «Сосуда»: разворот SpreadCard, оба таба, травмы 3/2/19 тестов; превью Vessel Card
6Улучшения Реликвии в данных + карточка Реликвииfast-tests + кадр
7Статистика и лор на табе «Дополнительно»кадр

Фазы 0 и 1 не пропускаются: без них экраны негде проверить, а перетаскивание, написанное внутри экрана, придётся переписывать на второй же странице.


8.1. Где мы сейчас (точка продолжения, 22.08.2026)

Сделаны фазы 0–5. 39 тестов зелёные, 34 коммита в dev.

Готово и живёт в кодеГде
Отряд из 8 мест, InBattle, склад предметов, 4-й слот по модели наградRunState, RunStateService, GameConfig
Команды состава и вещей во всех четырёх реализацияхIRunCommands и родня
Перетаскивание общим контроломDragManipulator, DropZoneManipulator
Страница «Отряд» и страница «Предметы» с проводкойPartyScreen*, ItemsScreen*
Панель осмотра компонентом, стоит на обеих страницахInspectPanel, InspectPanelPresenter
Карточка «Сосуда»: разворот с табами, травмы 3/2/1SpreadCard, VesselCard*
Дом рождается с людьми, забег их сажаетVesselFactory, IGuildRosterView

Следующий шаг — подключение к навигации игры. Сейчас экраны живут только в превью-стенде (Alebardium → UI Preview: Party, Items, Vessel Card). Нужно: открыть страницы из петли забега (вход через MenuRouter.OpenLoadout / UiNavigator), завести слой поверх экрана под карточку по ПКМ, связать ЛКМ по «Сосуду» с панелью осмотра. После этого появится первый кадр из игры — до сих пор ни один экран его не видел.

Ждёт одного рефреша редактора: типы VesselNamePool и поля _vesselItemSlotsMax, _vesselNamePool в GameConfig написаны, но Unity их не видел (Auto Refresh выключен). После рефреша заводятся ассет пула имён и заготовка перков — пока люди рождаются под ярлыком «Безымянный», а фабрика об этом кричит.

Блокирует фазу 6: улучшений Реликвии нет ни в RelicData, ни в контенте (§3.3).


9. Открытые вопросы — решить ДО кода

✅ Решено 2026-08-22 — четыре вопроса закрыты

Было вопросомРешениеЗапись
Чем помечена боевая четвёркаполе RosterSlot.InBattle, не порядок в массивежурнал
Старые сейвычитаем и расширяем молча, версию схемы не двигаемтам же
Статистика «Сосуда»счётчики на VesselStateтам же
Чем открываются места 7-8 и 4-й слотнаграда внутри забега — сгорает вместе с нимГД-журнал 2026-08-22/9

Следствие последнего, важное для кода: число открытых мест — состояние ЗАБЕГА, а не конфига. GameConfig держит базу (6) и потолок (8); сколько открыто сейчас — в RunState. Экран, читающий вместимость из конфига, покажет чужое число.

9.5. Панель осмотра в бою

Ставит ли паузу? Что происходит, когда осматриваемый погибает — окно закрывается, замирает или показывает «пал»?

9.6. Геймпад

ПКМ и перетаскивание — мышиные жесты. Чем заменяются: кнопка «осмотреть» + подтверждение, или режим перестановки?

9.7. Облик в облачении

Рендер живого UnitView в текстуру или собранный спрайт? Первое честнее и дешевле в поддержке, второе быстрее на экране.

9.8. Тултип и панель на одном экране

Остаётся ли наведение с тултипом там, где уже открыта панель осмотра, или тултип живёт только на складе, в наградах и внутри карточек?

9.9. Панель осмотра для врага

Тот же состав или урезанный (без снаряжения и перков)?

9.10. Где живёт вход на экран подготовки

Сейчас MenuRouter.OpenLoadout пушит полноэкранный оверлей. Открывается он с карты, из передышки, из обоих мест? Есть ли он в бою на паузе?


10. Что этот план НЕ трогает

  • Вкладка предметов отряда (Party-скоуп) — отложена Максом 22.08.2026.
  • Панель эффектов (баффы/дебаффы), второй дом травм — позже, учитывается только как направление.
  • Страницы «Реликвии» и «Поведение» — существуют в текущем экране, переезжают в ленту после того, как встанут первые две.