Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion creator/sdk7/2d-ui/onscreen-ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Build a UI by defining a structure of nested `UIEntity` objects in JSX. The synt

A simple UI with static elements can look a lot like HTML, but when you add dynamic elements that respond to a change in state, you can do things that are a lot more powerful.

The default Decentraland explorer UI includes a chat widget, a map, and other elements. These UI elements are always displayed on the top layer, above any scene-specific UI. So if your scene has UI elements that occupy the same screen space as these, they will be occluded.
The default Decentraland explorer UI includes a chat widget, a map, and other elements. These UI elements are always displayed on the top layer, above any scene-specific UI. So if your scene has UI elements that occupy the same screen space as these, they will be occluded. To keep your UI clear of these elements automatically, wrap it in the [`InteractableArea` component](ui-positioning.md#explorer-ui-insets-interactablearea).

See [UX guidelines](../design-experience/ux-ui-guide.md) for tips on how to design the look and feel of your UI.

Expand Down
35 changes: 34 additions & 1 deletion creator/sdk7/2d-ui/ui-positioning.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ The `UiCanvasInformation` component holds the following information:
* `height`: Canvas height in pixels
* `width`: Canvas width in pixels
* `devicePixelRatio`: The ratio of the resolution in physical pixels in the device to the pixels on the canvas
* `interactableArea`: A `BorderRect` object, detailing the area designated for scene UI elements. This object contains values for `top`, `bottom`, `left` and `right`, each of these is the number of pixels on that margin of the screen that are taken up by the explorer UI.
* `interactableArea`: A `BorderRect` object, detailing the area designated for scene UI elements. This object contains values for `top`, `bottom`, `left` and `right`, each of these is the number of pixels on that margin of the screen that are taken up by the explorer UI. Instead of reading these values manually, you can wrap your UI in the [`InteractableArea` component](#explorer-ui-insets-interactablearea) to apply them automatically.

{% hint style="warning" %}
**📔 Note** : Different Decentraland explorers will have different values for these, as the global UIs of the platform may differ, and the values might change dynamically as the user expands or hides different global UI menus.
Expand Down Expand Up @@ -369,3 +369,36 @@ Some other best practices regarding UI sizes:

* If the width or height of any UI element is dynamic, it's good to also use the `maxWidth`, `minWidth`, `maxHeight`, and `minHeight` parameters to make sure they stay within reasonable values.
* The font size of text is relative to a fixed number of pixels, you should make it dynamic so it remains readable on retina displays. See [Responsive text size](ui_text.md#responsive-text-size)

## Explorer UI insets (`InteractableArea`)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think insets doesn't clearly communicate that it refers to the interactive area.

Suggested change
## Explorer UI insets (`InteractableArea`)
## Explorer UI Interactable Area

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're totally right, it's not a good title
I renamed it to Safe Screen Area


The Decentraland explorer draws its own UI on top of every scene: the minimap, the chat window, the profile widget, and other overlays. These elements always render above scene UI, so anything you place under them is partly hidden and can't be clicked. How much of the screen they take up depends on the platform, and can change at any moment — for example when the player opens or closes the chat. The portion of the screen that's free of explorer UI is called the **interactable area**.

The `InteractableArea` component keeps your UI inside this region automatically, reading the current values that the explorer reports. Import it from `@dcl/sdk/react-ecs` and wrap the UI you want to protect:

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

export function setupUi() {
ReactEcsRenderer.setUiRenderer(() => (
<InteractableArea>
{/* A child sized 100% × 100% fills the interactable area exactly */}
<UiEntity
uiTransform={{ width: '100%', height: '100%' }}
uiBackground={{ color: Color4.create(0, 0, 0, 0.5) }}
/>
</InteractableArea>
))
}
```

`InteractableArea` positions itself absolutely using the inset values from the [`UiCanvasInformation` component](#responsive-ui-size), so the `positionType` and `position` fields of its `uiTransform` are reserved — any value you set for them is ignored. All other `uiTransform` properties (`padding`, `flexDirection`, `alignItems`, …) and UI components (`uiBackground`, `onMouseDown`, …) work as usual. The component reacts automatically whenever the explorer changes the reported area, for example when the player expands or hides a system menu.

{% hint style="info" %}
**📔 Note**: For now, only the **mobile client** (Godot) reports an interactable area, so the component only prevents overlaps there. Other clients will adopt it soon. Different explorers reserve different regions; when a client doesn't report an interactable area, the insets are `(0, 0, 0, 0)` and the component simply covers the whole screen, so it's always safe to leave in cross-platform UI code.
{% endhint %}

`InteractableArea` works just like the [`ScreenInsetArea` component](../building-for-mobile/safe-area.md#device-hardware-insets-screeninsetarea), but the two protect against different things: `InteractableArea` avoids the **explorer's own UI** (minimap, chat, overlays), while `ScreenInsetArea` avoids the **device's hardware-reserved margins** on mobile (notch, status bar, home indicator).

If you prefer to lay things out yourself, you can also read the raw inset values from `UiCanvasInformation.interactableArea`, described in [Responsive UI size](#responsive-ui-size).
4 changes: 4 additions & 0 deletions creator/sdk7/2d-ui/ui_text.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ A `Label` entity has the following fields that can be configured:

A `Label` entity can also have other common components found on other types of UI entities, like `uiTransform` and `uiBackground`.

{% hint style="info" %}
**💡 Tip**: To keep text legible, give it plenty of contrast against whatever is behind it. UI text has no outline property, so the recommended approach is to place the text over a solid `uiBackground` in a contrasting color. This matters especially for players on mobile, who may be viewing the screen under varying lighting conditions. For in-world text via [`TextShape`](../3d-essentials/text.md#text-shadow-and-outline-properties), use a thin outline instead.
{% endhint %}

_**ui.tsx file:**_

```ts
Expand Down
13 changes: 13 additions & 0 deletions creator/sdk7/3d-essentials/text.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,19 @@ The letters in the text can also have an outline in a different color surroundin
* `outlineWidth`: _number_. How wide the text outline will be, in all directions, as a number from 0 to 1. By default _0_, which makes it invisible.
* `outlineColor`: _Color3_ object. _Color3_ objects store an _RBG_ color as three numbers from 0 to 1.

{% hint style="info" %}
**💡 Tip**: It's a good practice to give your text a thin outline in a contrasting color. This keeps the text legible against whatever is behind it, as the background may vary with the scene's lighting conditions. This is especially important for players viewing the scene on mobile.

```ts
TextShape.create(sign, {
text: 'Hello World',
textColor: { r: 1, g: 1, b: 1, a: 1 },
outlineWidth: 0.1,
outlineColor: { r: 0, g: 0, b: 0 },
})
```
{% endhint %}

## Multiple lines

If you want your text to span multiple lines, use `\n` as part of the string. The following example has two separate lines of text:
Expand Down
31 changes: 30 additions & 1 deletion creator/sdk7/building-for-mobile/safe-area.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: Where scene UI can safely live on mobile — clear of the system HU

On a phone, two things eat into the screen space your UI can safely use:

* **The Decentraland system HUD** — the app overlays its own controls (joystick, chat, profile, camera controls, the interaction button). Scene UI placed under them clashes visually and competes for taps. These regions are mapped out in [Reserved margins](#reserved-margins) below.
* **The Decentraland system HUD** — the app overlays its own controls (joystick, chat, profile, camera controls, the interaction button). Scene UI placed under them clashes visually and competes for taps. These regions are mapped out in [Reserved margins](#reserved-margins) below, and the [`InteractableArea` component](#system-hud-insets-interactablearea) can keep UI clear of them automatically.
* **The device's hardware-reserved margins** — the notch or camera cutout, status bar, home indicator, and rounded corners. The SDK keeps UI clear of these automatically with the [`ScreenInsetArea` component](#device-hardware-insets-screeninsetarea).

The **mobile safe area** is what's left over — where scene UI can live without clashing with either.
Expand Down Expand Up @@ -86,6 +86,35 @@ Scene UI that overlaps the reserved regions will:
* Compete for taps with the system controls — players will accidentally trigger one or the other.
* Make your scene feel broken on mobile, which hurts featuring and retention.

## System HUD insets (`InteractableArea`)

The tables above are design-time guides: use them to plan your layout. At runtime, the explorer also **reports** the region that's currently free of its own UI — the **interactable area** — and the `InteractableArea` component constrains your UI to it automatically. Import it from `@dcl/sdk/react-ecs` and wrap the UI you want to protect:

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

export function setupUi() {
ReactEcsRenderer.setUiRenderer(() => (
<InteractableArea>
{/* A child sized 100% × 100% fills the interactable area exactly */}
<UiEntity
uiTransform={{ width: '100%', height: '100%' }}
uiBackground={{ color: Color4.create(0, 0, 0, 0.5) }}
/>
</InteractableArea>
))
}
```

`InteractableArea` positions itself absolutely using the inset values the explorer reports, so the `positionType` and `position` fields of its `uiTransform` are reserved — any value you set for them is ignored. All other `uiTransform` properties and UI components work as usual. The reported area can change at any moment — for example when the player opens or closes the chat — and the component reacts automatically.

{% hint style="info" %}
**📱 Mobile only (for now)**: Currently only the **mobile client** (Godot) reports an interactable area, so `InteractableArea` only prevents overlaps there. Other clients will adopt it soon. On clients that don't report a value, the insets are `(0, 0, 0, 0)` and the component covers the whole screen — safe to leave in cross-platform code, but not a substitute for testing. Always verify your layout on a real device using the [preview QR code](preview-on-mobile.md).
{% endhint %}

See [Explorer UI insets](../2d-ui/ui-positioning.md#explorer-ui-insets-interactablearea) for more details on this component.

## Device hardware insets (`ScreenInsetArea`)

The reserved margins above belong to the Decentraland **system HUD**. Separately, the **device hardware** reserves screen space for the notch or camera cutout, the status bar, the home indicator, and rounded corners. UI drawn underneath these is partly hidden or hard to tap.
Expand Down
3 changes: 2 additions & 1 deletion creator/sdk7/building-for-mobile/ui-best-practices.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ There is no single proven recipe for Decentraland mobile UI yet — the platform
## DOs

* **Design mobile-specific UIs**, or vary your UI by screen size and platform. Use [`isMobile()`](detect-platform.md) to branch.
* **Keep critical UI inside the [safe area](safe-area.md)**, and wrap it in [`ScreenInsetArea`](safe-area.md#device-hardware-insets-screeninsetarea) to clear the device's hardware margins (notch, status bar, home indicator).
* **Keep critical UI inside the [safe area](safe-area.md)**. Wrap it in [`InteractableArea`](safe-area.md#system-hud-insets-interactablearea) to clear the system HUD (joystick, chat, profile, action buttons) and in [`ScreenInsetArea`](safe-area.md#device-hardware-insets-screeninsetarea) to clear the device's hardware margins (notch, status bar, home indicator).
* **Minimize options.** Show only what the player needs right now and progressively disclose the rest.
* **Place actionable dialogs at the center of the screen** — anywhere a player needs to read and respond.
* **Place non-actionable messages at the top-center** — status, notifications, and ambient information.
* **Give text strong contrast against its background.** Mobile players often view their screens under suboptimal lighting, which makes reading harder. For 2D UI text, place it over a solid, contrasting [`uiBackground`](../2d-ui/ui_background.md). For in-world text via [`TextShape`](../3d-essentials/text.md#text-shadow-and-outline-properties), give it a thin outline in a contrasting color.

## DON'Ts

Expand Down
4 changes: 4 additions & 0 deletions creator/sdk7/design-experience/ux-ui-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ If you are going to place text that is displayed over imagery (or over the world

<figure><img src="../../images/media/ux-text-over-images.png" alt="Text over images" width="300"><figcaption><p>Prioritize legibility</p></figcaption></figure>

{% hint style="info" %}
**💡 Tip**: Backgrounds may vary with the scene's lighting conditions, and players on mobile often view their screens under suboptimal light. To keep text readable in every situation, always give it strong contrast against its background. For 2D UI text, place it over a solid, contrasting [`uiBackground`](../2d-ui/ui_background.md). For in-world text via [`TextShape`](../3d-essentials/text.md#text-shadow-and-outline-properties), give it a thin outline in a contrasting color.
{% endhint %}

### Icons

Icons synthesise information, helping you identify actions through images. They are an amazingly powerful tool for providing input that can be interpreted fast, as opposed to using text to label things, which demands more of the player’s attention and time. It’s also useful to show icons in combination with text, as this helps disambiguate their meanings.
Expand Down