Skip to main content

xgaida-x-nixi-uitk

UI Toolkit в Guildmaster: рантайм-экраны на UXML/USS, дизайн-система токенов, компоненты, MVVM и UI-тесты. Зови на любую работу с интерфейсом — экраны, стили, токены, custom controls, PanelSettings — и на всё под Assets/_Project/UI и Scripts/UI, даже если слова «UI Toolkit» в задаче нет. НЕ применять к: боевому uGUI-HUD (Image.Filled и родня), inspector-логике вне UITK, тех-доке об UI-слое (tech-scribe).

インストールへ移動

ソース情報

リポジトリ
Kaliguri/Guildmaster-Autobattler
ソースの最終更新活動
2026年8月6日 03:21
検出された SKILL.md の言語
ロシア語
スター
0
フォーク
0

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

ファイルエクスプローラー
5 ファイル

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
xgaida-x-nixi-uitk
description
UI Toolkit в Guildmaster: рантайм-экраны на UXML/USS, дизайн-система токенов, компоненты, MVVM и UI-тесты. Зови на любую работу с интерфейсом — экраны, стили, токены, custom controls, PanelSettings — и на всё под Assets/_Project/UI и Scripts/UI, даже если слова «UI Toolkit» в задаче нет. НЕ применять к: боевому uGUI-HUD (Image.Filled и родня), inspector-логике вне UITK, тех-доке об UI-слое (tech-scribe).
# UI Toolkit — рабочий контур Guildmaster Этот скилл — процедура, а не справка. Он превращает разрозненные правила в чеклист, который прогоняется на КАЖДОЙ UI-задаче. Цель — чтобы интерфейс собирался единообразно, из дизайн-системы, и попадал к Максу уже проверенным. ## Прежде всего: карта проекта Вся дизайн-система и экраны уже стоят. Ничего не изобретай — читай и продолжай. | Что | Где | |---|---| | Токены — ярус 1 (примитивы) | `Assets/_Project/UI/Theme/tokens.primitives.uss` | | Токены — ярус 2 (семантика) | `Assets/_Project/UI/Theme/tokens.semantic.uss` | | **Перечень элементов и их состояний** | `Scripts/UI/Components/UiComponentRegistry.cs` — ИСТОЧНИК, читают гейт, лист и звук | | Компоненты (`.gm-*`) | `Assets/_Project/UI/Theme/components/*.uss` — блок на файл | | Правила экранов | `Assets/_Project/UI/Theme/screens/*.uss` — экран на файл | | Агрегатор темы (импортит 3 яруса) | `Assets/_Project/UI/Theme/theme.uss` | | Экраны (UXML) | `Assets/_Project/UI/Screens/*.uxml` | | Гейт конвейера цвета | `Assets/_Project/Tests/EditMode/UI/UiColorPipelineTests.cs` | | Гейт состояний и порядка ярусов | `Tests/EditMode/UI/UiStateGateTests.cs` | | Гейт мёртвого (класс без стиля, стиль без класса) | `Tests/EditMode/UI/UssDeadCodeTests.cs` | | **Контактный лист состояний** | `Alebardium → UI → Contact Sheet` (в play) → `Temp/ContactSheet` | | Custom controls (C#) | `Assets/_Project/Scripts/UI/Components/*.cs` (неймспейс `Guildmaster.UI.Components`, префикс UXML `gm:`) | | Views / ViewModels / роутер | `Assets/_Project/Scripts/UI/*.cs` (неймспейс `Guildmaster.UI`) | | Рантайм-asmdef | `Guildmaster.UI.asmdef` | **Работаем в живой игре, а не на стендах** (реш. Макса 05.08.2026). Превью-стенд (`UI/Dev/UiPreviewRoot.uxml`, `PreviewPanelSettings.asset`) и витрина `Component Gallery` в проекте остаются, но из процедуры выведены: они отвечали на вопрос «как это выглядит в изоляции», а решение принимается по тому, как элемент выглядит В ИГРЕ — на живом фоне, в реальном соседстве, при своей подложке. Заодно отпадает целый класс ложных выводов: offscreen-рендер с `ppp=1` показывал обманный масштаб, а изолированный стенд — цвет без того, что под ним лежит. **Канва: 1920×1080.** Один UI-пиксель = один пиксель токена; всё проектируется под это разрешение. `PanelSettings`: `scaleMode = ScaleWithScreenSize`, `referenceResolution = 1920×1080`, `screenMatchMode = MatchWidthOrHeight`, `match = 1` (по высоте) — UI держит одну долю экрана на любом разрешении. **Нецелый скейл разрешён**, и это правило пережило отмену пиксель-арта: оно опирается не на стиль, а на то, что боевая камера ведёт зум непрерывно и в ровное кратное на экране не попасть. Множитель `scale = 1` — шов под будущую настройку UI-scale (доступность), в логике на `scale == 1` не закладываться. (Старые заметки про «640×360 ×3» / целочисленный `IntegerPanelScaler` — pixel-perfect отменён, удалено в Ф0 UI-реворка.) ## Пять правил, нарушение которых = переделка (HARD) Это не бюрократия — каждое правило закрывает конкретный способ, которым UI-код незаметно загнивает. Понимай «почему», тогда не придётся заучивать «нельзя». 1. **Разметка и стиль — только UXML/USS, никогда инлайн в C#.** Экран собирается как дерево `.gm-*`-классов в `.uxml`, вид задаётся в `.uss`. *Почему:* как только разметка расползается по C#, «единый стиль» из структуры превращается в устный договор, который никто не соблюдает. *Граница:* внутренности атомарного **custom control** (конструктор `SliderRow` создаёт свои `Label`/`Slider` кодом) — это НЕ нарушение. Правило про **композицию экранов**, а не про кишки переиспользуемого компонента. См. `references/component-model.md`. 2. **Значения — только через токены, не хардкод.** Цвета, отступы, размеры шрифта, рамки — через `var(--gm-*)`. Никаких магических `rgb(...)` или `24px` в `components.uss` и тем более в экранах. *Почему:* сменить тему/масштаб = поправить один ярус токенов. Хардкод ломает это. *Дисциплина ярусов:* экраны и `components.uss` консюмят ТОЛЬКО семантику; семантика ссылается ТОЛЬКО на примитивы. Прыгать через ярус нельзя. 3. **Текст — только через ключи локализации, заполнять только RU.** Любая видимая строка идёт через ключ (`ui.*`), русская локаль заполняется, остальные — прочерк. Прямые строки в UXML/C# = откат. *Почему:* ретрофит локализации по готовому UI — дорогая боль; ключ сразу стоит почти ноль. *Готча (добыто треком тултипов):* `StatValueFormatter` в настройках локализации обязан стоять **перед `DefaultFormatter`** и иметь пустое имя в списке имён. Иначе `{dmg}` молча напечатает имя структуры вместо числа; ловит `SmartStatStringTests`. 4. **⚠️ КАРТИНКА В ЧАТ НА КАЖДОЙ ИТЕРАЦИИ — ЖЕЛЕЗНО. Это правило Макс повторял в гневе.** **Кадр отправляется через `SendUserFile`.** `Read` PNG показывает картинку ТЕБЕ и до Макса не доходит — это не показ, а самопроверка. - Правило: **НИ ОДНОГО ответа про визуал БЕЗ картинки в этом же ответе.** Меняла раскладку, чинила баг, «вот стало лучше» — все три требуют свежего скрина В ЧАТЕ, не пересказа. - Ритм: ПО ХОДУ работы (сделал/поправил → показал → дальше), не пачкой к концу — короткая петля «показал → поправил» экономит время обоим. - Кадр — **из живой игры** (`ScreenCapture.CaptureScreenshot` в play), в честном 1920×1080. Крупный план (кроп зоны) помогает, когда обсуждается деталь, — но кроп это ДОБАВКА к кадру, а не замена. *Почему:* Макс делает визуальную приёмку по КАРТИНКЕ. Нет картинки в ответе — нет приёмки, он вынужден переспрашивать «где скрин», и это его бесит (по делу). Это самый частый мой провал — держи в голове ПЕРВЫМ. 5. **Тесты — под игру и ГДД, не наоборот.** Если UI-тест краснеет — чини UI или тест под реальное поведение, не ослабляй механику ради зелёного. ## Реф — ВХОД задачи, а не справка (06.08.2026) Разбор по архиву сессий: неверно прочитанный реф — САМЫЙ частый мой провал по UI (девять эпизодов из двадцати пяти) и самый дорогой: именно он даёт циклы по десять-двенадцать раундов на один элемент. Механика провала всегда одна — я работала по памяти о рефе, а не по разбору. **Порядок, от которого не отступать:** 1. **Открыть разбор ДО первой правки.** База — `Art_Dev/UI Refs/`, разборы — `_teardowns/*.md` на КЛАСС экрана (главное меню, настройки, награда…). Нет разбора на этот класс — сначала разбор, потом код. Правило самой базы: каждое утверждение со ссылкой на файл, размеры в долях экрана, «цвет — замером, а не глазами». 2. **Мерить ТОТ файл, что приложил Макс.** 06.08.2026 я померила саму игру-первоисточник вместо присланного им кадра и уверенно назвала числа не из того источника. Приложенный кадр — это заказ; игра-источник — справка. 3. **Перед показом — сравнить пару.** Реф и результат рядом, письменный список расхождений, и только потом «смотри». «Вот стало лучше» — не приёмка, а просьба сделать приёмку за меня. **Что я решаю сама, а что нет.** Разделение из README базы рефов: Макс — вкус и приёмка, я — замер и сведение. Значит «похоже ли» решает он, а «совпадает ли» обязана доказать я — числами и кадрами. ## Компонентная модель — ГИБРИД (как советует Unity) Развилка «темплейт или C#-контрол» решается по наличию логики/состояния: - **Нет логики — UXML-темплейт.** Чисто визуальный повторяющийся блок → `.uxml`-файл, вставляется через `<ui:Template>`/`<ui:Instance>`. Ноль C#. - **Есть логика/состояние — custom control.** `[UxmlElement] partial class : VisualElement` с `[UxmlAttribute]`-пропсами, `AddToClassList("gm-...")` в конструкторе, экспонируется в UXML под `gm:`. Эталон — `SliderRow`. - **Дублируется третий раз — выноси в компонент.** Скопировал разметку/стиль дважды — на третий делай переиспользуемый компонент. Инлайн-повтор в экранах не копи. - **Компонент — «префаб» интерфейса.** Один контрол + его USS-классы обслуживают ВСЕ вхождения: правишь `.gm-plate-button` — меняются все кнопки-пластины игры, правишь `.gm-mainmenu__btn` — только пункты меню, правишь токен — всё, что берёт эту роль. Отсюда правило: изменение вида вносится на том ярусе, где оно должно действовать, а не в ближайшем месте. Детали, примеры, старый vs новый синтаксис (`UxmlFactory`/`UxmlTraits` — deprecated) — в `references/component-model.md`. **Читай его перед созданием нового компонента.** ## USS-нейминг — BEM `block__element--modifier`. У нас это уже де-факто (`.gm-panel__title`, `.gm-button--primary`, `.gm-tab--active`). Держи единообразно; не используй имена типов (`Button`) и id-селекторы в стилях. Подробности и анти-примеры — в `references/component-model.md`. ## Данные ↔ UI — MVVM + runtime binding - **ViewModel — POCO**, создаётся через DI, НЕ MonoBehaviour, тестируется без сцены. Эталон — `SettingsViewModel` (baseline-снапшот, `event Changed`, `Begin/Save/Cancel`). - **VM → UI без эха:** обновляя контрол из VM, шли `SetValueWithoutNotify`, иначе словишь событие обратно и зациклишься. - Новые экраны — на этом паттерне. Детали и проводка View↔VM↔Router — в `references/screens-and-mvvm.md`. ## Размеры — против гигантизма (под 1080p) Философия «панели не на пол-экрана, читаемая типографика, ритм по сетке» держится, пороги — под 1920×1080. Конкретные значения — из токенов, не из головы. Быстрый чеклист (шкала отступов `--gm-space-*` = 8→64, шрифты `--gm-font-*` = 22→48) — в `references/live-session-and-screenshots.md`. ## Как я авторю UXML/USS 1. **Пишу файлы напрямую** (`Write`/`Edit`) — так я контролирую разметку и YAML. 2. **Проверяю в живой игре** через `execute_code`: обход дерева от `UIDocument.rootVisualElement`, чтение `resolvedStyle`, кадр через `ScreenCapture`. Превью-стенд и offscreen-рендер для этого больше не используются — см. следующий раздел. 3. **Namespace-префикс в UXML — всегда с `ui:` / `gm:`** (`<ui:Style>`, не `<Style>`), иначе UI Builder не откроет файл. ## Числа подбираются В ЖИВОМ play, а не перезаходами (реш. Макса 04.08.2026) Подбор вида — это петля «темнее / шире / мягче», и она обязана крутиться **не выходя из игры**. Правка файла на каждый шаг стоит выхода из play, переимпорта, входа обратно и потери состояния — за вечер это десятки минут его времени на ровном месте. **Как надо.** Макс входит в play, встаёт на нужный экран и НЕ выходит. Числа я правлю прямо в живой панели через `mcp__unityMCP__execute_code`: ищу элемент обходом дерева от `UIDocument.rootVisualElement`, ставлю `ve.style.*` (а приватные поля custom control — рефлексией) и зову `MarkDirtyRepaint()`. Он видит результат мгновенно. Сошлись — **тогда** записываю значения в USS/токены, и перезаход нужен ровно один, на проверку. **Готча приёма, на которой я села дважды подряд:** правка приватных полей рефлексией живёт **только до следующего пересчёта стиля**. Пересчёт случается не в момент вызова `ve.style.*`, а на следующем кадре, перечитывает USS (в живой сессии он ещё старый) и молча возвращает всё назад — выглядит как «агент вернул старый цвет». Лечение: вешать `RegisterCallback<CustomStyleResolvedEvent>`, который переустанавливает значения после каждого пересчёта, а не красить один раз. Инлайновый `ve.style.*` этим не страдает — он часть каскада. Границы приёма, обе важные: - **Так меняются только ЧИСЛА.** Формула, новое поле, новый элемент — это код: компиляция и перезаход неизбежны. Не делай вид, что подкрутил, если поменялась математика. - **Инлайн-стиль живёт до конца сеанса и НЕ является правкой.** Найденное значение обязано уехать в файл, иначе оно умрёт вместе с play mode. Правило 1 (никаких инлайнов) не нарушено: это измерительный прибор, а не авторинг. **Почему не Live Reload.** Штатный UI Toolkit Live Reload (тумблер в меню ⋮ Game view) для рантайма включён по умолчанию и умеет подхватывать USS/UXML на лету — но ему нужно, чтобы Unity ЗАМЕТИЛ правку файла, а **Auto Refresh у нас выключен** ради диеты компиляции. Оттого правка «не доезжает», и это выглядит как «стиль не применился». Включать Auto Refresh насовсем нельзя (вернётся переимпорт на каждое касание); включить его на сессию подбора UI — законный вариант, но гасить после. **И главное про переимпорт: пока идёт play, Unity ассеты НЕ переимпортирует.** `AssetDatabase.Refresh` отвечает успехом, а USS в живую панель не приезжает. Сказать «готово, смотри», не проверив `EditorApplication.isPlaying`, — это отправить Макса смотреть на старую картинку (поймано 04.08.2026, стоило трёх заходов). ## Цвет: одна дорога на экран, и она проверяется пипеткой **Условие, без которого разговор о палитре бессмысленен: что стоит в токене — то и на экране.** 05.08.2026 оно у нас не выполнялось (ручная конверсия душила заливки втрое), и подбор цвета шёл вслепую: любое названное Максом число превращалось на экране в другое. Сначала проверь равенство, потом обсуждай оттенки. **У цвета ДВЕ дороги, и вторая — источник дефектов:** | Дорога | Как идёт | Конверсия | |---|---|---| | штатная | USS → `background-color` / `border-color` / `Painter2D` | делает движок, значение задаётся ПРЯМОЕ | | ручная | USS → custom property → поле C# → `Vertex.tint` | делает шейдер UITK, поэтому наш код НЕ конвертирует | Обе дороги хотят одного и того же: **прямое значение из токена**. Нигде в UI-коде не должно быть `.linear`, `.gamma` или своей математики над цветом. Отказаться от ручной дороги нельзя: штатных градиентов в USS Unity не даёт и не планирует, а градиент на кнопке нам нужен. **Три правила, которые держат её чистой:** 1. **Ровно одна функция на весь UI — `PlateButton.VertexColor`, и она тождество.** Компонент, рисующий мешем, зовёт её, а не колдует у себя. 2. **У компонента нет своего цвета.** Дефолт поля — `Color.clear`, значение приходит только из USS. Иначе получается второй владелец, который однажды разойдётся с токеном (так было у `EdgeVeil`: токен 0.88, хардкод 0.92). 3. **Инвариант держит ТЕСТ, а не докстринг.** Комментарий не падает — и тот самый докстринг, который запрещал конверсию, сам же её и предписывал целые сутки. **Процедура подбора цвета — четыре шага:** 1. Цвет называется РОЛЬЮ (`--gm-color-surface-accent`), а не оттенком; оттенки живут ступенями рамп. 2. Крутим в живом play (см. раздел выше). 3. **Перед фиксацией — замер пикселя**, а не взгляд на скрин: снять кадр, взять точку внутри элемента, сравнить с заданным. Не сходится — это дефект конвейера, а не повод крутить число. 4. Найденное уходит в ТОКЕН, не в правило экрана. **Пипетка по рефу — законный способ задать цвет.** Если Макс утвердил кадр («верни именно этот цвет»), значения снимаются с кадра `getpixel`, а не подбираются на глаз, и в токен едут буквально. **Фаска следует за размером пластины** (правило Макса 05.08.2026). Поменял ширину кнопки — поменяй `--gm-plate-chamfer` в той же пропорции (360→320 ⇒ 10→9). Скол, оставленный крупным, читается как более резкая огранка у меньшей вещи: пропорция фигуры меняется, хотя «фигуру никто не трогал». То же касается любого размера, заданного в абсолютных единицах внутри компонента. ## Коммитить КАЖДОЕ изменение UI (правило Макса 05.08.2026) Работа по виду — это серия «покрутили → посмотрели → не то → назад». Без коммита на каждый шаг откатиться некуда: инлайновые пробы умирают с play-сессией, а файлы к тому моменту уже трижды переписаны. Поэтому: **изменение вида = отдельный коммит**, даже маленькое (цвет каймы, кегль, ширина). Дробить, а не копить пачкой — цена коммита секунды, цена потерянного варианта — вечер. ## Чеклист сдачи UI-задачи Прогнать перед тем, как сказать «готово»: - [ ] Разметка/стиль в UXML/USS, не в C# (кроме кишок custom control) - [ ] Ноль хардкод-значений — всё через `var(--gm-*)`, ярусы не перепрыгнуты - [ ] Весь текст через loc-ключи, RU заполнен - [ ] BEM-классы единообразны; новый/изменённый компонент есть в витрине - [ ] Новый экран — на MVVM (VM = POCO), VM→UI через `SetValueWithoutNotify` - [ ] Проект компилируется (`read_console` после C#-правок) - [ ] Числа подобраны в живом play, а не серией перезаходов; найденное уехало в USS - [ ] Цвет сверен ЗАМЕРОМ пикселя с тем, что задано в токене - [ ] Каждое изменение вида — своим коммитом, а не пачкой в конце - [ ] Перед «готово, смотри» проверено `EditorApplication.isPlaying` — иначе он смотрит старое - [ ] Тронул состояния или компонент — снят КОНТАКТНЫЙ ЛИСТ и показан - [ ] Новый элемент есть в `UiComponentRegistry`, гейты `UiStateGateTests` и `UssDeadCodeTests` зелёные - [ ] Работа по рефу — открыт разбор, сравнение пары «реф ↔ результат» со списком расхождений - [ ] Скрин Максу в реальном масштабе (1920×1080) ## Справочные файлы (читать по надобности) - `references/component-model.md` — темплейты vs custom controls, BEM, синтаксис Unity 6, антипаттерны. Читать перед созданием компонента. - `references/screens-and-mvvm.md` — MVVM-проводка, роутер, биндинг, DI. - `references/live-session-and-screenshots.md` — петля работы в живом play, снятие кадра, замер пипеткой, чеклист размеров под 1080p и самопроверка перед показом. **Основной файл процедуры.** - `references/ui-testing.md` — `com.unity.ui.test-framework`, PanelSimulator, смоук-тесты кликов.
GitHubで見る