# Система аватаров: основа `avatar_base` реализует независимое состояние аватара: группы, именованные пресеты, композицию целевых значений и JSON-состояние для сохранений. Зависимости от диалогов, боевых персонажей и Live2D нет. Полный формат и контракт: [en.md](en.md). ## Управление ```csharp IAvatar avatar = AvatarCatalog.Create("my_game/marao"); avatar.ApplyPresets(new Dictionary { ["emotion"] = "angry", ["eyes_state"] = "opened" }); AvatarFrame target = avatar.Resolve(); AvatarState saved = avatar.CaptureState(); ``` Контентный мод зависит от `avatar_base>=1` и объявляет сущности `Kind: avatar`. У определения есть `Id`, `Renderer`, `BaseValues` и `Groups`. У группы — `Default`, `Priority`, `Presets`; у пресета — `Values`. Имена групп и пресетов произвольные, регистрозависимые. Значения пресетов — целевые привязки для конкретного рендера, а не универсальные числа от 0 до 1. Каждая группа выбирает один пресет. Изменение группы сохраняет остальные группы. Все изменения проверяются до применения: опечатка не оставляет частично изменённое состояние. Неизвестные значения отклоняются, автоматических подмен нет. Композиция начинается с `BaseValues`, затем применяет группы по возрастанию `Priority`, при равенстве — по имени (ordinal). Более поздняя группа перекрывает одноимённую привязку целиком. Порядок команд ничего не меняет. Например, эмоция имеет приоритет 0, явное состояние глаз — 100. Пустой пресет `auto` не вносит привязок и тем самым возвращает управление эмоции. Это обычное имя, не ключевое слово. `Resolve()` возвращает полный неизменяемый снимок, без оставшихся значений прошлого пресета. `CaptureState()` — отдельный DTO с ID аватара и выбором пресетов. При восстановлении отсутствующие группы получают значения по умолчанию, неизвестные группы/пресеты и чужой ID отклоняются. Изменения ресурсов не меняют уже созданный экземпляр: владелец пересоздаёт его при перезагрузке. ## Граница реализации `IAvatarRenderer` задаёт контракт визуального адаптера: корневой `Control`, применение полного целевого состояния, время перехода и освобождение принадлежащих ему ресурсов. Мод `avatar_layers` уже выбирает и отображает PNG-слои. Будущий адаптер Live2D будет выбирать параметры модели. `AvatarRenderers.Create(avatar)` находит фабрику по `Renderer` и применяет начальное состояние. После изменений владелец явно вызывает `renderer.Apply(avatar.Resolve())`. Фабрики автоматически регистрируются и удаляются вместе с модами через стандартный `ModTypeConsumer`. В этой версии нет адаптера Live2D, сценарных команд, редактора, проверки совместимости картинок и автоматической интеграции с сохранениями. Существующие диалоговые аватарки работают как прежде. JSON-пример и правила владения ресурсами приведены в английской документации. Тесты проверяют независимость экземпляров, приоритеты, атомарность, сериализацию и загрузку настоящего ресурса.