> For the complete documentation index, see [llms.txt](https://docs.allout.game/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.allout.game/all-out-docs/ru/ui/uidoc-quick-start.md).

# Быстрый старт UIDoc

***

UIDoc позволяет описывать игровой интерфейс с помощью HTML и CSS, а затем передавать его изменяющиеся данные и обрабатывать его события в CSL. Это полезно для меню, инвентарей, деревьев навыков и других структурированных экранных интерфейсов.

UIDoc похож на браузер, но это не встроенный веб-браузер. Используйте поддерживаемое подмножество, описанное в [Поддержка HTML и CSS в UIDoc](/all-out-docs/ru/ui/uidoc-html-css-support.md).

## Создайте ресурс UIDoc

Создайте папку в каталоге вашей игры `res` Каталог. Имя папки должно заканчиваться на `.uidoc` и содержать `index.html` и `index.css`:

```
res/
└── UI/
    └── settings.uidoc/
        ├── index.html
        └── index.css
```

Пути к ресурсам, используемые CSL, являются относительными по отношению к `res`, поэтому этот документ загружается как `UI/settings.uidoc`.

## Редактируйте визуально и генерируйте CSL

Выберите ресурс UIDoc в редакторе All Out, чтобы открыть его визуальный режим авторинга. Вы можете выделять и перетаскивать элементы на холсте, изменять их размер, менять их порядок или родительские связи в Layers, а также редактировать общие свойства HTML и CSS в инспекторе. Предпросмотр рендерится самой средой выполнения UIDoc, поэтому он использует ту же поддерживаемую раскладку и то же поведение рендеринга, что и игра.

Инспектор Interface выводит динамические поля, повторяющиеся списки, элементы ввода и действия из разметки документа. Сохранение ресурса, такого как `ui/shop.uidoc` также поддерживает `scripts/generated/uidoc/ui/shop.csl`. Его типизированная обёртка предоставляет `default_data`, `decode_event`, считыватели ввода и `draw`, поэтому игровому коду не нужно повторять низкоуровневые привязки, показанные далее в этом руководстве:

```csl
data := UiShop_UIDoc.default_data();
data.title = "Store";
UiShop_UIDoc.draw(data, player, shop_event);
```

Сгенерированный код использует те же публичные `UI.uidoc_*` вызовы, описанные ниже; он не добавляет отдельную систему времени выполнения и не меняет API среды выполнения UIDoc.

При использовании инструментов автоматизации, `uidoc_create_asset` возвращает версию его шаблона и точное сгенерированное `index.html`/`index.css` содержимое. Ресурсы UIDoc не перезагружаются «на лету» в запущенной игре, поэтому перезапустите игру после изменения этих файлов. Используйте `uidoc_diagnostics` для проверок компиляции и области просмотра, а затем `uidoc_runtime_inspect` для проверки живых узлов, привязок, стилей, данных клика и прямоугольников.

## Напишите документ

В `index.html`:

```html
<div class="screen">
  <div class="panel">
    <span class="title">Settings</span>
    <span class="message">{{message}}</span>
    <button class="close" data-on-click="event:close">Close</button>
  </div>
</div>
```

`{{message}}` — это текстовая привязка. `data-on-click` отправляет `UIDoc_Event` в CSL.

В `index.css`:

```css
.screen {
  position: fixed;
  inset: env(safe-area-inset-top) env(safe-area-inset-right)
         env(safe-area-inset-bottom) env(safe-area-inset-left);
  display: flex;
  align-items: center;
  justify-content: center;
}

.panel {
  display: flex;
  flex-direction: column;
  width: 420px;
  padding: 24px;
  gap: 16px;
  color: white;
  background: #172033;
  border: 2px solid #52627d;
  border-radius: 12px;
  box-shadow: 0 12px 28px 0 #00000066;
}

.title {
  font-size: 32px;
  text-align: center;
}

.close {
  height: 48px;
  background: #3559a8;
  border-radius: 8px;
}

.close:hover {
  background: #4770ca;
}

.close:pressed {
  background: #29447f;
}
```

Отступы safe-area сохраняют полноэкранный интерфейс в стороне от вырезов устройства и области верхней панели игры.

## Привязывайте и отрисовывайте его из CSL

Отрисовывайте интерфейс игрока из `ao_late_update` стека вызовов. Перед отрисовкой документа каждый кадр очищайте и заново создавайте привязки UIDoc:

```go
settings_uidoc_event :: proc(event: UIDoc_Event, userdata: Object) {
    player := userdata.(Player);
    if player == null return;

    if event.handler == "event:close" {
        player.settings_open = false;
    }
}

draw_settings :: proc(player: Player) {
    UI.uidoc_clear_bindings();
    UI.uidoc_bind_text("message", "Changes are saved automatically.");

    document := get_asset(UIDoc_Asset, "UI/settings.uidoc");
    if document == null return;

    UI.uidoc(document, false, player, settings_uidoc_event);
}

Player :: class : Player_Base {
    settings_open: bool;
    pet_name: string;

    ao_late_update :: method(dt: float) {
        if this.is_local_or_server() && this.settings_open {
            draw_settings(this);
        }
    }
}
```

Колбэк получает точную строку обработчика из `data-on-click`. Неповторяющийся элемент управления может задать статический `data-key` для `event.key`; повторяющиеся элементы управления используют свой разрешённый `data-for-key` или ключ элемента списка.

`userdata` передаётся только в этот колбэк; он не идентифицирует документ. Каждый ресурс UIDoc может быть отрисован один раз за одну симуляционную отправку. Когда документ перестаёт отрисовываться, его текущая активация закрывается; повторная отрисовка автоматически назначает новую генерацию активации, чтобы устаревшие реплицированные макеты не могли прикрепиться к вновь открытому документу. Одновременно может быть активировано не более четырёх различных ресурсов UIDoc.

Доступные привязки верхнего уровня:

```go
bind_player_fields :: proc(player: Player) {
    UI.uidoc_bind_bool("visible", true);
    UI.uidoc_bind_text("name", player.get_username());
    UI.uidoc_bind_float("cameraSize", player.camera.size);
}
```

## Условия, привязки рисования и списки

Используйте `data-if` для включения узла только пока привязка верхнего уровня типа bool истинна. Необязательный ведущий `!` инвертирует её. `data-if` не вычисляет выражения, локальные для списка, такие как `item.visible`; повторяющееся визуальное состояние следует задавать через локальную для списка привязку рисования, а повторяющуюся структурную или интерактивную видимость следует определять при построении списка CSL. Для другого динамического визуального состояния оставляйте классы статическими и привязывайте поддерживаемый цвет или непрозрачность:

```html
<div
  class="notice"
  data-if="showNotice"
  data-style-color="noticeColor">
  {{noticeText}}
</div>
```

Привяжите `noticeColor` с помощью `UI.uidoc_bind_text` с использованием поддерживаемой строки цвета CSS. Атрибуты class компилируются как статические токены классов и не поддерживают `{{...}}` интерполяцию.

Используйте `data-for` для повторяющихся данных:

```html
<div class="inventory">
  <button
    class="item"
    data-for="item in items"
    data-for-key="item.id"
    data-key="inventory-item"
    data-style-color="item.rarityColor"
    data-on-click="event:item">
    {{item.name}}
  </button>
</div>
```

Сформируйте этот список в CSL перед вызовом `UI.uidoc`:

```go
Inventory_Row :: struct {
    id: string;
    name: string;
    rarity_color: string;
}

bind_inventory_rows :: proc(items: []Inventory_Row) {
    UI.uidoc_begin_list("items");
    for item: items {
        UI.uidoc_list_item(item.id);
        UI.uidoc_list_bind_text("id", item.id);
        UI.uidoc_list_bind_text("name", item.name);
        UI.uidoc_list_bind_text("rarityColor", item.rarity_color);
    }
    UI.uidoc_end_list();
}
```

Используйте стабильное, уникальное прямое выражение, такое как `data-for-key="item.id"` для каждого повторяющегося элемента. Оно возвращается как `event.key`. Передавайте `UI.uidoc_list_item(...)` то же стабильное значение, чтобы взаимодействие, ввод и идентичность прокрутки сохранялись при изменениях списка. Статический `data-key` обозначает роль элемента управления; UIDoc объединяет эту роль с привязанным ключом каждого вложенного элемента списка и его текущим индексом, чтобы сформировать зарегистрированную идентичность во время выполнения.

В приведённом выше примере имя живого теста содержит суффикс, например `inventory-item#potion-42:7/__widget`. Проверьте точное имя в `client_ui_tree`, а затем нацеливайтесь на этот экземпляр по полному имени или достаточно точному суффиксу, например `Test.click_button("inventory-item#potion-42:7")`. Поиск только по роли, например `Test.click_button("inventory-item")` неоднозначен, когда видно несколько строк. `data-on-click` а видимый текст не является селектором теста. Вложенные списки добавляют одну `#key:index` пару на каждый цикл.

## Поля ввода

Привяжите поле ввода с помощью `data-bind-value`:

```html
<input
  id="pet-name"
  class="name-input"
  placeholder="Pet name"
  data-bind-value="petName"
  data-on-click="event:name-input">
```

Считайте его текущее значение после отрисовки документа:

```go
draw_pet_name_input :: proc(player: Player, document: UIDoc_Asset) {
    UI.uidoc_bind_text("petName", player.pet_name);
    UI.uidoc(document, false, player, settings_uidoc_event);
    player.pet_name = UI.uidoc_text_value(document, "pet-name", player.pet_name);
}
```

`UI.uidoc_text_value` находит поле ввода по его `id` или `data-key`, а затем возвращает текущее значение его `data-bind-value` привязки.

## Прокрутка и масштабирование

Прокрутка включается через overflow в CSS. Обе оси можно включить в одном и том же вьюпорте:

```html
<div class="viewport" data-scroll-zoom="zoom">
  <div class="canvas">
    <button
      class="node"
      data-for="node in nodes"
      data-for-key="node.id"
      data-key="canvas-node"
      data-style-transform-x="node.x"
      data-style-transform-y="node.y"
      data-on-click="event:node">
      {{node.name}}
    </button>
  </div>
</div>
```

```css
.viewport {
  width: 100%;
  height: 100%;
  overflow-x: auto;
  overflow-y: auto;
}

.canvas {
  position: relative;
  width: 1600px;
  height: 1000px;
}

.node {
  position: absolute;
  width: 160px;
  height: 64px;
}
```

Привяжите `масштабирование` с помощью `UI.uidoc_bind_float`. `data-scroll-zoom` масштабирует позиции, размеры, текст, изображения, области попадания и пределы прокрутки содержимого относительно центра вьюпорта. Оставляйте фиксированные элементы управления масштабом вне масштабируемого вьюпорта.

{% hint style="warning" %}
Атрибуты выражений привязки используют прямое выражение, такое как `data-for-key="node.id"`, `data-style-transform-x="node.x"`, или `data-scroll-zoom="zoom"`. Не помещайте эти выражения внутрь `{{...}}`. Интерполяция Mustache предназначена для текста и `src`; классы и `data-key` значения статичны.
{% endhint %}

Для обычной панели прокрутки опустите `data-scroll-zoom`. Перетаскивание сдвигает по каждой включённой оси; колесо прокручивает по вертикали, а по горизонтали — только когда включён только горизонтальный overflow.

## Распространённые ошибки

* Загружайте документ, используя его путь относительно `res`, включая `.uidoc` суффикс.
* Отрисовывайте его из UI-кода локального игрока под `is_local_or_server()`.
* Вызывайте `UI.uidoc_clear_bindings()` и перед каждой отрисовкой передавайте текущие привязки.
* Отрисовывайте каждый ресурс UIDoc один раз за обновление. Используйте `userdata` только как данные колбэка.
* Используйте `data-if` только с привязками верхнего уровня типа bool. Привязывайте локальное для списка визуальное состояние через `data-style-opacity`/`data-style-color`, либо исключайте структурные/интерактивные строки из привязанного списка.
* Назначайте повторяющимся узлам стабильное прямое `data-for-key` выражение; оставляйте `data-key` статическим при именовании роли элемента управления.
* Рассматривайте поддержку CSS как зависящую от конкретного свойства и значения. `auto` и `none` принимаются только там, где они перечислены в сгенерированной справке, боковые границы, такие как `border-bottom` не поддерживаются, а `calc(...)` ограничен документированными полями длины с простой сложением/вычитанием.
* Задавайте содержимому прокрутки реальный размер. Одних только трансформаций не следует использовать как его единственный размер раскладки.
* Используйте собственную адаптивную раскладку и поведение масштабирования UIDoc вместо применения второго ручного масштаба UI в CSL.
