План привести дизайн-систему к тому, как надо, вырезав легаси. Правила — в Reference - UI Design System; здесь — диагноз с числами, что взято из разбора чужой системы, фазы работ и то, от чего отказываемся осознанно.

Повод: 04.08.2026, Макс — «Т.е. у нас вообще не должны мочь брать цвета из палитры. Мы можем брать цвета из РОЛИ» и «Режем, уничтожаем легаси, делаем как надо. Слишком часто это нам аукалось».


1. Диагноз: что есть на 04.08.2026

96 примитивов, 103 роли. Раскладка ролей вскрывает главное:

Группа ролейШтук
цвет86
гарнитуры7
контуры5
габариты диалога3
внутреннее поле панели1

Семантический ярус существует только для цвета. Длительности переходов, прозрачность выключенного, зазоры со смыслом — ролей не имеют вовсе; компонент берёт их числом или ступенью шкалы. Пример из свежего кода: длительность сдвига пункта меню написана как 0.12s прямо в правиле.

Семнадцать мест берут цвет мимо ролей (components.uss), из них девять — --gm-brass-300, включая базовые кнопки. Это не единичная небрежность: правило живёт комментарием в шапке файла, проверки нет, и нарушения копились месяцами. Последнее добавила я сама 04.08.2026, перенеся цвет титула из старого кода не глядя.

Сироты копятся молча. Рампа ember осиротела при развороте палитры и была найдена глазами; storm пересекается с patina по смыслу и до сих пор не разведён.


2. Что взято из Bloodlines-Dark-UI

Наша же дизайн-система для Asset Store (Assets/Alebardium/DesignSystem) решает те же задачи дальше нас. Что оттуда стоит забрать, а что нет:

Механизм тамЧто делаетБерём?
ThemeSchema отдельно от ThemeDefinitionсписок ролей отдельно от их значений → несколько тем поверх одного словаряда, когда дойдём до нескольких стилей (фаза 5)
ThemeDoctorтипизированные проблемы с автофиксом: роль не заполнена (Error), ссылка битая (Error), значение без роли — сирота (Info), шрифт не назначен (Warning)частично: сироты и битые ссылки — фаза 4
поиск «UI без темы»находит элементы, не подключённые к ролямда, это и есть наш гейт яруса (фаза 1)
TextStyleTokenDefкегль + межбуквенное + интерлиньяж + цвет одной рольюнет: в USS эту роль играют классы
InteractionTokenDefвсе пять состояний + тайминг одним токеном на слотнет как токен, да как идея: состояния компонента должны жить в одном месте (фаза 3)
слоты и блупринтыкомпонент объявляет цветные места, тема заполняетнет: у нас USS-каскад, слоты избыточны

3. Фазы

Порядок обязателен: каждая следующая опирается на предыдущую.

Фаза 1 — гейт яруса и резка легаси

ИСПОЛНЕНА. Гейт заведён 04.08.2026 (TokenTierTests), переведено девятнадцать мест, заведено семь новых ролей — число «семнадцать» ниже относится к замеру на день написания плана и осталось как есть. Последний литерал цвета (зерно главного меню) снят 06.08.2026 ролью --gm-color-menu-grain: до этого дня гейт был красным. Тогда же исполнена и часть фазы 3 — состояния сведены в перечень UiComponentRegistry и закрыты гейтом UiStateGateTests.

  1. Тест: ступень палитры (var(--gm-<рампа>-<число>)) в components.uss и в экранных USS = красный, с именем файла и номером строки. Исключения — три вынужденных случая из справочника.
  2. Починить семнадцать мест. Часть потребует новых ролей — это нормальный исход, а не обход: отсутствие роли означает дыру в словаре смыслов.
  3. storm — развести с patina или удалить. Решение за Максом, откладывать больше нельзя: два токена с одним смыслом — это и есть «роль для галочки».

Результат фазы: взять цвет мимо роли становится невозможно, а не «не принято».

Фаза 2 — роли для не-цвета

Завести и применить: --gm-motion-* (длительности и кривые переходов), --gm-opacity-disabled, именованные отступы там, где у зазора есть смысл («внутреннее поле панели», «шаг пунктов меню»). Гейт фазы 1 на шкалы НЕ распространяется — см. «Шкалы против палитры» в справочнике.

Фаза 3 — компоненты

  1. Компоненты раскладки (Stack / Section / панель со слотами) — закрыть долг, из-за которого экран собирается из голых VisualElement, а автор обязан помнить про flex-shrink и прокрутку. Открыт с 04.08.2026, тянет за собой миграцию экранов.
  2. Состояния компонента — в одном месте. Сейчас :hover / :active / :focus / :disabled дублируются в каждом компоненте, и половина правил существует ради войны специфичности с темой Unity (.unity-button.gm-*). Свести к одному набору правил на семейство.
  3. Инвентаризация: что уже компонент, что копипаста разметки, чего не хватает под ближайшие экраны.

Фаза 4 — перепись ролей (доктор в миниатюре)

Скрипт печатает: роли без единого потребителя, ссылки в никуда, ступени палитры, на которые не смотрит ни одна роль. Не тест, а инструмент уборки — красным быть не обязан.

Фаза 5 — несколько стилей (только когда понадобится)

Роли фиксированы, палитр может быть несколько (Макс: «палитра у нас может быть хоть 999999 цветов под 4-6 стилей»). Предусловие — фаза 1: пока хоть один компонент висит на ступени, смена стиля поедет наполовину. Механика — как ThemeSchema / ThemeDefinition в Bloodlines.


4. От чего отказываемся, и почему

  • Component-токены (--gm-button-primary-bg под каждый компонент) — третий словарь, который надо синхронизировать с двумя. Каждый случай, где он «нужен», у нас означает нехватку роли.
  • Автоматический гейт контраста — решение Макса 04.08.2026: «лучше оставь это на мои глазочки… Без оверинженеринга». Следствие принимаем честно: числа контраста в комментариях USS перестают быть поддерживаемой правдой и читаются как ориентир на момент подбора. Если больно станет — вернёмся.
  • Текстовый стиль одним токеном — в USS его роль уже играют классы.
  • Слоты и блупринты — модель чужого рантайма (uGUI + инспектор), у нас USS-каскад.