> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/creator/content-creator-zh/chang-jing-sdk7/2d-ui/onscreen-ui.md).

# 屏幕 UI

了解如何为场景中的玩家创建 UI。例如，这对于显示与游戏相关的信息很有用。

你可以为你的场景构建一个 UI，将其显示在屏幕固定的 2D 空间中，而不是 3D 世界空间中。

只有当玩家站在场景的 LAND 地块内时，UI 元素才可见，因为相邻场景可能有自己的 UI 要显示。UI 的某些部分也可以在世界空间中发生某些事件时被触发打开，例如玩家点击某个特定位置时。

通过定义一个嵌套的 `UiEntity` 对象结构来构建 UI，使用 JSX。用于 UI 的语法与 [React](https://reactjs.org/) （一个非常流行的、基于 JavaScript 的网页 UI 构建库）。

{% hint style="warning" %}
**📔 注意**：你只能在具有 `.tsx` 扩展名的文件中定义 UI 语法。 `.tsx` 文件支持 `.ts` 文件支持的一切内容，并且还支持 UI 语法。我们建议创建一个 `ui.tsx` 文件，并在其中定义你的 UI。记得从 `index.ts` 中调用你的 UI 渲染方法，使用 `ReactEcsRenderer.setUiRenderer(yourUiMethodName)`，参见下面的示例。
{% endhint %}

一个带有静态元素的简单 UI 看起来很像 HTML，但当你加入会响应状态变化的动态元素时，你就可以做出强大得多的事情。

默认的 Decentraland 浏览器 UI 包括聊天组件、地图以及其他元素。这些 UI 元素总是显示在最上层，位于任何场景专属 UI 之上。因此，如果你的场景中有占用相同屏幕空间的 UI 元素，它们会被遮挡。

参见 [UX 指南](/creator/content-creator-zh/chang-jing-sdk7/she-ji-ti-yan/ux-ui-guide.md) ，了解如何设计你的 UI 外观和体验的提示。

{% hint style="info" %}
**📱 为移动设备设计**：设备会为刘海、状态栏、Home 指示条和圆角预留屏幕空间，客户端还会在画布的一部分上绘制自己的控件。你不需要计算这些——请使用下面的 [`screenInset`](#screen-inset-area) 来选择 UI 所放置的区域。它默认使用设备安全区域，因此无需你额外处理硬件边距。在发布前，请查看 [移动端安全区域](/creator/content-creator-zh/wei-yi-dong-duan-gou-jian/kai-fa/safe-area.md) 和 [移动端 UI 最佳实践](/creator/content-creator-zh/wei-yi-dong-duan-gou-jian/kai-fa/ui-best-practices.md).
{% endhint %}

当玩家点击屏幕右下角的 *关闭 UI* 按钮时，所有 UI 元素都会隐藏。

## 渲染 UI

要在你的场景中显示 UI，请使用 `ReactEcsRenderer.setUiRenderer()` 函数，并传入一个有效的实体结构，该结构在一个 `.tsx` 文件。

每个实体都定义为一个类似 HTML 的节点，并为其每个组件提供属性。

***ui.tsx 文件：***

```ts
import { UiEntity, ReactEcs } from '@dcl/sdk/react-ecs'
import { Color4 } from '@dcl/sdk/math'

export const uiMenu = () => (
  <UiEntity
    uiTransform={{
      width: 700,
      height: 400,
      margin: { top: '35px', left: '500px' },
    }}
    uiBackground={{ color: Color4.Red() }}
  />
)
```

***index.ts 文件：***

```ts
import { ReactEcsRenderer } from '@dcl/sdk/react-ecs'
import { uiMenu } from './ui'

export function main() {
    ReactEcsRenderer.setUiRenderer(uiMenu, { virtualWidth: 1920, virtualHeight: 1080 })
}
```

你还可以定义一个实体结构，并在同一条命令中将其渲染出来， `.tsx` 文件。

***ui.tsx 文件：***

```tsx
import ReactEcs, { ReactEcsRenderer, UiEntity } from '@dcl/sdk/react-ecs'
import { Color4 } from '@dcl/sdk/math'

export function setupUI() {
  ReactEcsRenderer.setUiRenderer(() => (
    <UiEntity
      uiTransform={{
        width: 700,
        height: 400,
        margin: { top: '35px', left: '500px' },
      }}
      uiBackground={{ color: Color4.Red() }}
    />
  ), { virtualWidth: 1920, virtualHeight: 1080 })
}
```

***index.ts 文件：***

```ts
import { setupUI } from './ui'

export function main() {
    setupUI()
}
```

{% hint style="warning" %}
**📔 注意**：你的所有 UI 元素都需要嵌套到同一个结构中，并且在结构根部只有一个单一父级。你只能在场景中调用 `ReactEcsRenderer.setUiRenderer()` 一次。
{% endhint %}

## UI 实体

UI 中的每个元素都必须定义为一个单独的 `UiEntity`，无论它是图片、文本、背景、不可见的对齐框等等。就像场景的 3D 空间中一样，每个 `UiEntity` 都有自己的组件来赋予它位置、颜色等。

类似 React 的语法允许你将每个组件指定为 `UiEntity`中的一个属性，这使得代码更短、更易读。

在 `UiEntity` 中使用的组件与普通实体中使用的组件不同。你不能将 UI 组件应用到普通实体上，也不能将普通组件应用到 UI 实体上。

以下组件可用于 `UiEntity`:

* `uiTransform`
* `uiBackground`
* `uiText`
* `onMouseDown`
* `onMouseUp`
* `onMouseEnter`
* `onMouseLeave`
* [`uiInputBinding`](/creator/content-creator-zh/chang-jing-sdk7/2d-ui/ui_input_binding.md) —— 当元素被按住时持续保持输入操作，用于构建自定义控件

和 HTML 标签一样，你可以将组件定义为自闭合，或将一个嵌套在另一个之中。

{% hint style="danger" %}
**警告：** 保持全屏布局包装器不要带指针处理器。向 `onMouse` 处理器，或 `pointerFilter: 'block'`，添加到一个 `UiEntity` 尺寸 `100%` 乘以 `100%` 上，会使它捕获屏幕上的每一次点击，让你所有其他 UI 以及整个 3D 世界都无法点击。请把处理器放在真正需要它们的面板或按钮上。参见 [指针阻挡](/creator/content-creator-zh/chang-jing-sdk7/2d-ui/ui_button_events.md#pointer-blocking).
{% endhint %}

***ui.tsx 文件：***

```tsx
import ReactEcs, { ReactEcsRenderer, UiEntity } from '@dcl/sdk/react-ecs'
import { Color4 } from '@dcl/sdk/math'

export const uiMenu = () => (
  // 父级实体
  <UiEntity
    uiTransform={{
      width: 200,
      height: 200,
      margin: { top: '250px', left: '500px' },
    }}
    uiBackground={{ color: Color4.Blue() }}
  >
    {/* 自闭合的子实体 */}
    <UiEntity
      uiTransform={{
        width: 400,
        height: 400,
        margin: { top: '35px', left: '500px' },
      }}
      uiText={{ value: `你好，世界！`, fontSize: 40 }}
    />
    {/* 父级实体的闭合语句 */}
  </UiEntity>
)
```

***index.ts 文件：***

```ts
import { ReactEcsRenderer } from '@dcl/sdk/react-ecs'
import { uiMenu } from './ui'

export function main() {
    ReactEcsRenderer.setUiRenderer(uiMenu, { virtualWidth: 1920, virtualHeight: 1080 })
}
```

UI 模块的定义只能有一个父级实体。你可以定义任意多的其他实体，但它们都必须放在顶部只有一个单一父级的结构中。

## 屏幕虚拟缩放

为 UI 设置一个虚拟宽度和高度。这样可以确保你的 UI 在不同屏幕尺寸下看起来都一样，而不受实际像素屏幕大小影响。

```ts
export function setupUi() {
    ReactEcsRenderer.setUiRenderer(uiComponent, { virtualWidth: 1920, virtualHeight: 1080 })
}
```

如果你将虚拟宽度设为 1920、虚拟高度设为 1080，UI 就会按比例缩放以适应屏幕大小。如果屏幕是 1920x1080，UI 将以与虚拟尺寸相同的大小显示。如果屏幕更大或更小，任何像素值都会按比例缩放以适应虚拟尺寸。例如，如果屏幕是 3840x2160，那么定义为宽度 100 像素的元素将显示为 200 个实际像素。

UI 缩放系数实际用于乘以像素值的计算是 [`Math.min(realWidth / virtualWidth, realHeight / virtualHeight)`](https://github.com/decentraland/js-sdk-toolchain/blob/main/packages/%40dcl/react-ecs/src/system.ts).

### 默认虚拟尺寸

虚拟尺寸是可选的，但它的两个维度必须成对出现：要么同时传入，要么都不传入。当你不传入其中一个时，平台默认值会被应用：

| 平台       | 默认虚拟尺寸      |
| -------- | ----------- |
| 移动端      | `1600x720`  |
| 桌面端和 Web | `1920x1080` |

这意味着，即使你完全不传任何选项，你的 UI 中的像素值也始终会相对于一个参考分辨率进行缩放。当场景仅使用 `addUiRenderer()` 且从不调用 `setUiRenderer()`.

三种特殊情况：

* **取消缩放**：传入一个无效尺寸——任何 `0` 或更小的值——即可完全禁用虚拟屏幕。此时像素值会被当作原始画布像素使用，不进行任何缩放。这是关闭虚拟屏幕的文档化方式，因此不会记录日志。

  ```ts
  ReactEcsRenderer.setUiRenderer(uiComponent, { virtualWidth: 0, virtualHeight: 0 })
  ```
* **不完整的尺寸**：只给出两个维度中的一个也是无效的，因此它会像上面的情况一样禁用虚拟屏幕——平台默认值会介入。 **不是** 与上面的取消禁用不同，这种情况会被报告：只给出一半尺寸是错误而不是有意选择，因此 SDK 会记录 `不完整的虚拟屏幕尺寸（…）：两个维度都是必需的，因此虚拟屏幕已被禁用，并且未应用 UI 缩放。` 每种尺寸一次。请同时传入两个维度，或者都不传。

  ```ts
  // 不要这样做——完全不会应用任何缩放
  ReactEcsRenderer.setUiRenderer(uiComponent, { virtualWidth: 1920 })
  ```

  在主渲染器上尤其值得再次检查，因为那里的不完整尺寸也是一个场景级开关：任何提到 `setUiRenderer()` 的调用 *其中任一* 维度都会优先于任何 `addUiRenderer()`，因此上面的示例会为整个场景禁用虚拟屏幕，并丢弃传递给额外渲染器的有效尺寸。
* **移动端上的 16:9 尺寸**：手机屏幕比 16:9 宽得多，因此 16:9 的虚拟画布会让 UI 出现上下黑边。如果你传入一个 16:9 尺寸（`1920x1080`, `1280x720`，…）且场景运行在移动端，它会被覆盖为 `1600x720`，并且控制台会记录一次消息。移动端上非 16:9 的尺寸，以及桌面端或 Web 上所有有效尺寸，都会按原样保留。

{% hint style="info" %}
**📔 注意**： `vw` 和 `vh` 单位独立于虚拟屏幕： `1vw` 是画布宽度的 1% `1vh` 是画布高度的 1%，与 CSS 中完全相同。它们也会忽略 [`screenInset`](#screen-inset-area)，因此在默认的 `'device'` 内放入一个 `width: '100vw'` 会比一个 `width: '100%'` 更宽——前者覆盖整个屏幕，后者填满内嵌区域。
{% endhint %}

{% hint style="info" %}
**📱 注意**：平台检测是异步解析的。在最初几帧里，SDK 还不知道自己正在移动端运行，因此虚拟屏幕一开始会是 `1920x1080` ，然后在检测完成后切换为 `1600x720` —— 你可能会看到 UI 在加载时短暂重新缩放，而 16:9 覆盖消息会在场景开始后不久出现在控制台中。如果你想从第一帧开始就拥有一个稳定的单一参考分辨率，请传入明确的非 16:9 虚拟尺寸。
{% endhint %}

{% hint style="warning" %}
**📔 在此 SDK 版本之前编写的场景有何变化**

有三项变更会影响现有场景。它们都不是可选启用的，因此一个完全未被改动的场景，在更新其 SDK 版本后外观仍会有所不同：

1. **虚拟屏幕现在默认启用。** 过去，一个未传入任何选项的场景会将像素值按原始画布像素进行布局。现在它会相对于 `1920x1080` (`1600x720` （移动端上）进行缩放。要恢复之前的行为，请显式关闭虚拟屏幕，使用 `setUiRenderer(ui, { virtualWidth: 0, virtualHeight: 0 })`.
2. **`screenInset` 默认为 `'device'`.** 你的 UI 现在放置在设备安全区域内，因此在移动端它会向内移动，而根级 `100%` 不再是整个屏幕——全屏背景、遮罩和覆盖层会停留在刘海和 Home 指示条之外。要恢复之前的行为，请传入 `setUiRenderer(ui, { screenInset: 'none' })`。见 [屏幕内边距区域](#screen-inset-area).
3. **`devicePixelRatio` 不参与 UI 布局。** 按像素大小设置的 UI 现在在高密度（视网膜和移动端）屏幕上会比以前大 2 到 3 倍。 **这一项没有可选关闭方式** —— 请重新检查任何经过手工微调的尺寸，并移除场景为自己计算的任何缩放系数。
   {% endhint %}

## 屏幕内边距区域

屏幕并不能完全自由使用：手机会为刘海、状态栏、Home 指示条和圆角预留空间，而每个浏览器都会在画布的一部分上绘制自己的 HUD（小地图、聊天等）。渲染器的可选 `screenInset` 属性用于选择你的 UI 所放置的屏幕区域：

| 值                              | UI 放置的区域                                                                |
| ------------------------------ | ----------------------------------------------------------------------- |
| `'device'` *（默认）*              | 设备安全区域，不包括刘海、状态栏和圆角。从 `UiCanvasInformation.screenInsetArea`.            |
| `'interactable'`               | 中读取。 `浏览器报告为不含自身 HUD（小地图、聊天等）的区域。从`UiCanvasInformation.interactableArea |
| `。具体覆盖范围由各浏览器决定——请在你目标的平台上验证。` | 整个屏幕，左上角有 `0,0` 。                                                       |

```ts
// UI 会避开刘海、状态栏和圆角——这是默认行为
ReactEcsRenderer.setUiRenderer(uiComponent, { virtualWidth: 1920, virtualHeight: 1080 })

// UI 会避开浏览器自身的 HUD
ReactEcsRenderer.setUiRenderer(uiComponent, { screenInset: 'interactable' })

// UI 覆盖整个屏幕，由你自己处理边距
ReactEcsRenderer.setUiRenderer(uiComponent, { screenInset: 'none' })
```

在桌面端，设备内边距为零，因此 `'device'` 在那里会把 UI 放在整个屏幕上——效果与 `。具体覆盖范围由各浏览器决定——请在你目标的平台上验证。`相同。该区域会在每个 tick 重新读取，因此当内边距变化时，例如在旋转或系统栏出现/隐藏时，UI 会跟着变化。

{% hint style="warning" %}
**📔 `'interactable'` 在桌面端不是空操作。** 与设备内边距不同，可交互区域在 *不是* 桌面客户端中为零：它会将大约屏幕左侧 25% 的区域留给自己的 UI，因此 `screenInset: 'interactable'` 会把你的 UI 放在其余 75% 的区域中。这正是该选项的目的，但这也意味着它会改变你的桌面布局——如果你只想在手机上使用，请用 [`isMobile()`](/creator/content-creator-zh/wei-yi-dong-duan-gou-jian/kai-fa/detect-platform.md) 分支处理。

**客户端支持**: `'interactable'` 需要一个会报告该区域的浏览器。它在桌面端受支持，在移动端则从客户端版本 `1.12.1` 及以上开始支持——在更旧的移动端客户端上，该值会被报告为零，而 UI 会退回到覆盖整个屏幕。相同的 `1.12.1` 版本还会统一 `'device'` 区域在 Android 和 iOS 之间的差异，所以在任何依赖这两种内边距之一的布局中，都应将其视为下限。 `。具体覆盖范围由各浏览器决定——请在你目标的平台上验证。` 在各处的行为都相同。
{% endhint %}

{% hint style="warning" %}
**📔 注意**：不要把你的 UI 包裹在 [`ScreenInsetArea` 或 `InteractableArea`](/creator/content-creator-zh/wei-yi-dong-duan-gou-jian/kai-fa/safe-area.md#wrap-part-of-your-ui-instead) 组件中，同时还保留渲染器上的匹配 `screenInset` 值——这样内边距会被应用两次，使 UI 因双倍边距而向内移动。要么依赖 `screenInset`，要么将其设置为 `。具体覆盖范围由各浏览器决定——请在你目标的平台上验证。` ，然后自己放置包装器。
{% endhint %}

### 真实设备上的三个区域

下面的截图是在同一部手机上、同一个场景下得到的，分别只更改了 `screenInset` 值并渲染了三次。洋红色矩形是 UI 本身；轮廓线是浏览器报告的区域——青色是整个画布，琥珀色是 `screenInsetArea`，绿色是 `interactableArea`.

<figure><img src="https://2460066822-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-78aa0fa3423a3ed51b5889f0150484a354b2dd30%2Fscreeninset-none.png?alt=media" alt="Scene UI covering the whole phone screen, including the notch strip and the areas under the client controls"><figcaption><p><code>screenInset: 'none'</code> —— UI 覆盖整个画布。它的角落位于刘海下方以及客户端自身控件的后面。</p></figcaption></figure>

<figure><img src="https://2460066822-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-94c4b28274282d30cda22c389b375fa30c78dc64%2Fscreeninset-device.png?alt=media" alt="Scene UI inset to the device safe area, clear of the notch"><figcaption><p><code>screenInset: 'device'</code> （默认值）—— UI 会收进设备安全区域，避开刘海和圆角。不过它仍然会与客户端的控件重叠，因为那些控件不属于该区域。</p></figcaption></figure>

<figure><img src="https://2460066822-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-c0c75a80bed756d6b2b1483a7cca0cadef26c77e%2Fscreeninset-interactable.png?alt=media" alt="Scene UI inset to the area the client reports as free of its own HUD"><figcaption><p><code>screenInset: 'interactable'</code> —— UI 被放置在客户端为场景 UI 指定的矩形区域内。在这里捕获的移动客户端 <code>1.12.1</code>上，这不包括左侧栏（个人资料、聊天、摇杆）；右下角的操作按钮则是按设计绘制在该区域上的。</p></figcaption></figure>

{% hint style="info" %}
**💡 提示**: `'interactable'` 让你获得每个浏览器为场景 UI 指定的区域。这故意并不等同于“所有客户端控件都在其外部”——正如第三张截图所示，移动端操作按钮会被刻意绘制在该区域上方。你放在它们下面的任何内容仍然可以被你触达，但会与相同的点击竞争，因此要牢记 [拥挤的角落](/creator/content-creator-zh/wei-yi-dong-duan-gou-jian/kai-fa/safe-area.md#where-the-client-controls-live) ，并检查你的目标平台：该区域具体覆盖哪些内容由每个浏览器自行决定，并且可能会在不同版本之间变化。
{% endhint %}

每个渲染器都会遵守自己的 `screenInset`，因此主 UI 和任何通过 `addUiRenderer()` 添加的 UI 可以同时使用不同的区域。与虚拟尺寸不同，这个值从不在渲染器之间共享。

## 多个 UI 模块

如果你的场景包含多个各自定义 UI 的系统或模块，你可以使用 `ReactEcsRenderer.addUiRenderer()`来分别渲染每个 UI 模块。这在处理包含多个 UI 组件的复杂场景时尤其有用，或者在为一个 [智能物品](https://github.com/decentraland/docs/tree/main/creator/sdk7/smart-items/smart-items.md)定义 UI 时也很有用，因为它应该能够独立于场景其余代码中的内容而被使用。

该 `ReactEcsRenderer.addUiRenderer()` 函数要求你提供一个实体作为 UI 的所有者。这可以是任何实体，甚至可以是一个仅用于作为 UI 所有者而创建的虚拟实体。

```ts
export function setupUi() {

    // 创建一个虚拟实体作为 UI 的所有者
    const dummyEntity = engine.addEntity()

    // 将 UI 模块定义为一个返回 UI 模块数组的函数
    const uiComponent = () => [
      // 返回一个 UI 模块的函数，
      // 返回一个 UI 模块的函数
      // ...
    ]

    // 以虚拟实体作为所有者渲染 UI 模块
    ReactEcsRenderer.addUiRenderer(dummyEntity, uiComponent)
}
```

这个代码片段可以独立于场景中的任何其他 UI 代码而存在。场景的其余部分可能包含一个 `ReactEcsRenderer.setUiRenderer()`，也可能完全不包含任何内容，而 UI 仍然会被渲染出来。

一个 `addUiRenderer()` 调用也可以像 `setUiRenderer()`一样包含虚拟宽度和高度。不过，如果场景还有一个 `setUiRenderer()` 调用也定义了虚拟宽度和高度，那么 `addUiRenderer()` 调用中的虚拟宽度和高度将被忽略。

```tsx
ReactEcsRenderer.addUiRenderer(dummyEntity, uiComponent, { virtualWidth: 1920, virtualHeight: 1080 })
```

虚拟尺寸是一个全场景共享的单一值，其解析方式如下： `setUiRenderer()` 上的尺寸优先；否则，第一个 `addUiRenderer()` 提供过该值的调用优先；如果没有任何渲染器提供该值，则应用 [平台默认值](#default-virtual-size) 。只带有 `screenInset` 的选项不算作已提供的尺寸。

该 [`screenInset`](#screen-inset-area) 则正好相反——它是按渲染器分别生效的，所以每个 UI 模块都可以位于不同的屏幕区域：

```tsx
// 这个小部件会避开浏览器 HUD，不管主 UI 使用什么区域
ReactEcsRenderer.addUiRenderer(dummyEntity, uiComponent, { screenInset: 'interactable' })
```

可使用 `ReactEcsRenderer.removeUiRenderer(dummyEntity)` 移除；另外，如果拥有该 UI 的实体被销毁，UI 也会被移除。如果再次为同一个实体调用 `ReactEcsRenderer.addUiRenderer()` ，但传入不同的 UiRenderer，之前的会被清理，新对象会取而代之。

### 共享一条 setUiRenderer 语句

而不是为每个 UI 模块都调用 `ReactEcsRenderer.addUiRenderer()` ，你可以只调用 `ReactEcsRenderer.setUiRenderer()` 一次，并传入一个 UI 模块数组，这些模块可以位于不同文件中。

```ts
const uiComponent = () => [
  // 返回一个 UI 模块的函数，
  // 返回一个 UI 模块的函数
  // ...
]

ReactEcsRenderer.setUiRenderer(uiComponent, { virtualWidth: 1920, virtualHeight: 1080 })
```

下面是一个更完整的示例：

***ui.tsx 文件：***

```ts
export function UIModule1() {
  return (
    <UiEntity
      uiTransform={{
        flexDirection: 'column',
        alignItems: 'center',
        justifyContent: 'space-between',
        positionType: 'absolute',
        position: { right: '3%', bottom: '3%' },
      }}
    >
      <Label value="你好，世界！" fontSize={18} textAlign="middle-center" />
    </UiEntity>
  )
}

export function UIModule2() {
  return (
    <UiEntity
      uiTransform={{
        flexDirection: 'column',
        alignItems: 'center',
        justifyContent: 'space-between',
        positionType: 'absolute',
        position: { right: '3%', top: '3%' },
      }}
    >
      <Label
        value="这里还有更多 UI！"
        fontSize={18}
        textAlign="middle-center"
      />
    </UiEntity>
  )
}
```

***index.ts 文件：***

```ts
import { ReactEcsRenderer } from '@dcl/sdk/react-ecs'
import { UIModule1, UIModule2 } from './ui'

export function main() {
    ReactEcsRenderer.setUiRenderer(() => [
      UIModule1(),
      UIModule2(),
      // ...
      // 下面这一行是为了使用 DCL UI Toolkit 库
      // https://github.com/decentraland-scenes/dcl-ui-toolkit
      ui.render(),
    ], { virtualWidth: 1920, virtualHeight: 1080 })
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.decentraland.org/creator/content-creator-zh/chang-jing-sdk7/2d-ui/onscreen-ui.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
