Сборка экрана из готовых компонентов игры¶
Экран описывается в YAML — компоненты и данные, без координат. Вёрстку
раскладывает flexbox, а хром (панели, кнопки, рамки, бары, ячейки навигации)
берётся из библиотеки спрайтов игры по таблице ролей role-map.yaml.
Генерируется только то, чего в игре нет: задник и иллюстрации.
Сборка — два прохода¶
Растяжимые панели надо запечь в плоский PNG под тот размер, который они в
итоге займут, а размер известен только после раскладки: карточки — flex:1 1 0,
их высота это остаток после шапки и навигации. Поэтому сначала рендер, потом
замер, потом сборка заново.
BUILD="uv run --project art-generator python -m art_generator.screen_build \
--spec game_design_features/guild/screen-s3a-real.yaml \
--kit game_design_features/_ui-kit \
--kit game_design_features/guild/art-kitmode \
--role-map game_design_features/_ui-kit/role-map.yaml \
--asset-index game_design_features/_ui-kit/asset-index.json \
--out game_design_features/guild/screen-s3a-real.html \
--report game_design_features/guild/coverage-s3a.md"
$BUILD # 1. первый рендер
uv run --project art-generator python art-generator/scripts/measure_boxes.py \
game_design_features/guild/screen-s3a-real.html --out /tmp/boxes.json
$BUILD --boxes /tmp/boxes.json # 2. пересборка с запечёнными плитами
Второй проход обязателен, если файл пойдёт в Figma. Без --boxes плиты
остаются на CSS border-image. В браузере это верно, а html.to.design
border-image не умеет: правило вырождается в border-style:solid дефолтного
цвета, и панель приезжает чёрным прямоугольником в толщину своего борта.
Так уже случилось — пять карточек и шапка. Проверка:
grep -c border-image game_design_features/guild/screen-s3a-real.html # должно быть 0
В конце печатается строка вида 28 parts: 20 from the game's library, 8
generated. Отчёт --report расписывает это по деталям: какая роль, какой
спрайт ответил и как он был выбран — решением таблицы, точным именем из спека
или поиском. Поиск — единственный из трёх, который догадка.
Без --role-map и --asset-index сборка работает по-старому: весь хром
берётся из сгенерированного кита. Так можно проверить, что изменилось от
привязки к библиотеке.
Дальше в Unity — обязательно с картой спрайтов¶
$BUILD --boxes /tmp/boxes.json \
--sprite-map-out game_design_features/guild/sprite-map-s3a.json
# после импорта в Figma:
overlord/tools/figma_unity_pipeline/import_figma.sh \
--screen GuildS3a --file-key <KEY> --root-id <ID> \
--library-map game_design_features/guild/sprite-map-s3a.json
Без --library-map экспорт выгрузит копию каждой взятой из игры детали в
Assets/Sprites/UI/<Screen>/ — двадцать дубликатов на экран, каждый с новым
GUID. Это ровно то дублирование, ради устранения которого весь сборщик и
писался, только на шаг позже.
Сверка по хешу здесь не спасает: она сравнивает внутри одной папки, а
библиотека лежит в Assets/InternalAssets/Sprites/UI. Расширить сверку тоже
не выход — Figma рендерит узел в его размере по вёрстке, и кнопка 290x109,
выгруженная как 178x67, даёт другой хеш, чем исходный спрайт. Знание о том,
какой файл ответил, есть только у сборщика — он его и записывает.
Проверки¶
# пропорции: метки одной роли обязаны рендериться одного размера
uv run --project art-generator python art-generator/scripts/audit_proportions.py \
game_design_features/guild/screen-s3a-real.html \
--kit game_design_features/_ui-kit --kit game_design_features/guild/art-kitmode \
--asset-index game_design_features/_ui-kit/asset-index.json
# анти-паттерны вёрстки (59 правил)
node .claude/skills/impeccable/scripts/detect.mjs \
game_design_features/guild/screen-s3a-real.html
Аудит возвращает код 1, если внутри одной роли разброс ≥8%. Детектор молчит, когда всё чисто; если сомневаетесь, что он вообще работает, прогоните его на файле с заведомой ошибкой — на 9px тексте и цветном glow он даёт четыре находки.
Переиндексировать библиотеку¶
Нужно после того, как художник добавил или переименовал спрайты:
uv run --project art-generator python art-generator/scripts/index_ui_assets.py \
--root overlord/frontend/unity/Assets/InternalAssets/Sprites/UI \
--out game_design_features/_ui-kit/asset-index.json
Индекс тянет из Unity-.meta границы 9-slice, поэтому растяжимые панели
растягиваются так, как их задумал художник, а не background-size: 100% 100%.
Что править, если деталь выглядит не так¶
Почти всегда — role-map.yaml, а не код. Роль → спрайт решается там, один
раз на всю игру. Ищите кандидатов по метаданным индекса, а не по именам
папок: заявка «в игре нет тянущейся по всем сторонам панели» была написана
после поиска только в Shared/ — панель нашлась в LoadingScreen/. И не
верьте именам: NavBar/icon_selected — это красный крестик закрытия.