> 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, поэтому он использует ту же поддерживаемую схему компоновки и рендеринга, что и игра.

Инспектор интерфейса определяет динамические поля, повторяющиеся списки, поля ввода и действия по разметке документа. При сохранении ресурса, такого как `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_diagnostics` для проверки авторинга и области просмотра в редакторной области. Используйте `uidoc_runtime_inspect` для живых узлов, привязок, стилей, данных клика и прямоугольников; по умолчанию использует активного клиента, пока работает Start Game, иначе требует явного `scope: "editor"`. В каждом ответе рантайма указывается его область.

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

В `index.html`:

```html
<div class="screen">
  <div class="panel">
    <span class="title">Настройки</span>
    <span class="message">{{message}}</span>
    <button class="close" data-on-click="event: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 inset удерживают полноэкранный интерфейс UI вдали от вырезов устройства и области верхней панели игры.

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

Отрисовывайте UI игрока из `вызова 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", "Изменения сохраняются автоматически.");

    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` чтобы включать узел только пока привязка верхнего уровня типа boolean истинна. Необязательный ведущий `!` инвертирует её. `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` привязки.

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

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

```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;
}
```

Привяжите `zoom` с помощью `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`. Перетаскивание перемещает по каждой включённой оси; колесо прокручивает вертикально или горизонтально, когда включено только горизонтальное переполнение.

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

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