You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs: UI defaults follow-ups (review of #76) (#77)
* docs: correct UI defaults follow-ups on top of #76
Review follow-ups verified against @dcl/react-ecs on the merged branch.
- build-ui/SKILL: an incomplete virtual size does not warn. There is no such
log in react-ecs; the only console.log is the mobile 16:9 override. Since
the skill tells an agent to trust that warning, the wrong claim is worse
here than in prose.
- build-ui/SKILL: add the scene-wide consequence of an incomplete size --
setUiRenderer wins the arbitration if it mentions either dimension, so it
disables the virtual screen for the whole scene and discards a valid size
passed to addUiRenderer, silently.
- ui-components: UiCanvasInformation width/height are RAW canvas pixels, not
"virtual/scaled units when a virtual size is set". The SDK derives the scale
factor from them, so they cannot already be scaled. This matters for the
slider helper, which divides by them.
- build-ui/SKILL, advanced-input/SKILL: the "~3x scaling for mobile" rule of
thumb survived in both files, one of them in a paragraph this branch
rewrote. With dpr out of the scale factor most of that 3x is already
applied, and the 1600x720 mobile virtual screen adds ~1.2x more.
- build-ui/SKILL, ui-components: 'interactable' is recommended for whole-UI
application without a client floor. It needs an explorer that reports the
area: mobile client 1.12.1 onwards, which is also the release that
normalizes the 'device' area between Android and iOS. Older clients report
no margins and the inset silently does nothing.
The 7.26.0 version gate is left as written -- confirmed as the release number.
* fix: the incomplete-size case does log, the <= 0 opt-out is the silent one
My earlier correction was verified against the cherry-picked branch, not
against what merged. Commit 2c1128ff added isPartialVirtualSize() and a
once-per-size console.log, so main carries two logs in @dcl/react-ecs and the
original wording was right for this case.
The distinction is still worth stating, inverted: a value <= 0 is the
documented opt-out and stays silent; a half-given size is treated as a
mistake and is reported. Both disable the virtual screen either way.
Copy file name to clipboardExpand all lines: advanced-input/SKILL.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -236,7 +236,7 @@ Key facts from the mobile docs expansion (commit `17ca7be`):
236
236
-**Touch-only input** -- no mouse hover states, keyboard shortcuts, or right-click.
237
237
-**`borderRadius` unsupported on mobile UI** -- avoid rounded corners in mobile-targeting scenes.
238
238
-**Static HUD** -- the mobile client has fixed on-screen controls (joystick, action buttons) that cannot be repositioned or customized from the scene.
239
-
-**UI designed for desktop needs ~3x scaling for mobile readability.**
239
+
-**The old "~3x scaling for mobile" rule no longer applies as written.** On SDK 7.26.0+ pixel-sized UI is already ~2–3× larger on a phone than before (`devicePixelRatio` was removed from the UI scale factor), and the mobile virtual screen (`1600x720` vs desktop's `1920x1080`) adds ~1.2× more. Start from the desktop sizes, measure on a device, and scale up only what comes up short. See [[build-ui]].
240
240
-**UI is kept inside the device's safe area (notch, home indicator) automatically on SDK 7.26.0+** — the renderer's `screenInset` option defaults to `'device'`. Only pass `screenInset: 'none'` if you want the UI over the whole screen; the `ScreenInsetArea` component is then available to inset individual subtrees. Below 7.26.0, wrap the UI in `ScreenInsetArea` (from `@dcl/sdk/react-ecs`) yourself. See [[build-ui]].
241
241
-**SDK features not yet on mobile:** ParticleSystem, scene dynamic lights (PBPointLight), AudioAnalysis, nine-slice UI tile mode. Check the docs for the latest feature parity tracker.
Copy file name to clipboardExpand all lines: build-ui/SKILL.md
+6-4Lines changed: 6 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -36,15 +36,17 @@ The options argument is optional at the API level. **On SDK 7.26.0+, omitting it
36
36
| No virtual size passed, mobile |`1600x720`|
37
37
| A 16:9 size passed (e.g. `1920x1080`), mobile | overridden to `1600x720`, logged once to console |
38
38
| A non-16:9 size passed | used as-is on every platform |
39
-
| A size with any value `<= 0`| virtual screen **disabled** — raw canvas pixels, no scaling |
40
-
| Only one of the two dimensions passed | also **disabled** (both are required), and warns once to the console|
39
+
| A size with any value `<= 0`| virtual screen **disabled** — raw canvas pixels, no scaling. Silent: this is the documented opt-out|
40
+
| Only one of the two dimensions passed | also **disabled** (both are required), and logged once per size — it is treated as a mistake, not an opt-out|
41
41
42
42
So on 7.26.0+, `{ virtualWidth: 0, virtualHeight: 0 }` — not omitting the options — is how you opt into raw-pixel layout. Only do that if the user explicitly asks for it. **Below 7.26.0 there are no defaults: omitting the options is what disables scaling.** See the version gate below.
43
43
44
44
Because the default rule above has you pass the size explicitly either way, generated code behaves identically on both sides of that boundary — which is a second reason to always pass it.
45
45
46
46
The virtual size is scene-wide, resolved as: the size on `setUiRenderer` wins → else the first `addUiRenderer` that passed one → else the platform default. Options carrying only a `screenInset` don't count as a passed size.
47
47
48
+
Note that `setUiRenderer` wins the arbitration if it mentions *either* dimension, even when the size is incomplete and therefore invalid. So `setUiRenderer(ui, { virtualWidth: 1920 })` disables the virtual screen for the whole scene and discards a valid size passed to any `addUiRenderer`. The SDK logs it once per size, but the scene still loses its virtual screen. Never emit a single dimension.
49
+
48
50
API (verified against `@dcl/react-ecs`, file `dist/system.d.ts`):
**ScreenInsetArea** — Wrapper that keeps children inside the device's hardware-reserved margins (notch, status bar, home indicator, rounded corners). **Usually unnecessary now: `screenInset` defaults to `'device'`, which already does this for the whole renderer.** Reach for the component only when the renderer opted out with `screenInset: 'none'` and you want to protect just one subtree — wrapping on top of the default double-applies the inset. On mobile it positions itself absolutely using the insets the device reports; on desktop the insets are `(0,0,0,0)`, so it's a no-op. It owns its own `positionType` and `position`; any values you pass for those in `uiTransform` are ignored. All other `uiTransform` props (`padding`, `flexDirection`, `alignItems`, …) and components (`uiBackground`, `onMouseDown`, …) work as usual. A child sized `width: '100%', height: '100%'` fills the safe area exactly. Distinct from the *Decentraland system HUD* reserved zones (joystick, chat, profile, interaction button) — those still need to be avoided manually. UI designed for desktop typically needs sizes scaled ~3× for mobile readability.
123
+
**ScreenInsetArea** — Wrapper that keeps children inside the device's hardware-reserved margins (notch, status bar, home indicator, rounded corners). **Usually unnecessary now: `screenInset` defaults to `'device'`, which already does this for the whole renderer.** Reach for the component only when the renderer opted out with `screenInset: 'none'` and you want to protect just one subtree — wrapping on top of the default double-applies the inset. On mobile it positions itself absolutely using the insets the device reports; on desktop the insets are `(0,0,0,0)`, so it's a no-op. It owns its own `positionType` and `position`; any values you pass for those in `uiTransform` are ignored. All other `uiTransform` props (`padding`, `flexDirection`, `alignItems`, …) and components (`uiBackground`, `onMouseDown`, …) work as usual. A child sized `width: '100%', height: '100%'` fills the safe area exactly. Distinct from the *Decentraland system HUD* reserved zones (joystick, chat, profile, interaction button) — avoid those with `screenInset: 'interactable'` or by hand. Do **not** apply the old "scale sizes ~3× for mobile" rule of thumb on 7.26.0+: with `devicePixelRatio` out of the scale factor, pixel-sized UI is already ~2–3× larger on a phone than it used to be, and the `1600x720` mobile virtual screen adds ~1.2× on top. Start from the desktop sizes and only scale up what actually measures too small on a device.
122
124
123
-
**InteractableArea** — Wrapper that keeps children inside the renderer-reported *interactable area* — the part of the screen NOT covered by the client's own UI (minimap, chat window, platform overlays). Reads `UiCanvasInformation.interactableArea` and constrains children via absolute positioning; on the Unity desktop client the left ~25% of the screen is reserved, so children fill the remaining ~75%. **Prefer `screenInset:'interactable'` on the renderer for a whole-UI application**; use the component for a single subtree, or when the renderer uses a different inset. Like `ScreenInsetArea`, it owns `positionType`/`position` (values you pass are ignored) and falls back to zero insets (no-op) when unavailable. Import from `@dcl/sdk/react-ecs`; usage `<InteractableArea><MyHud /></InteractableArea>`. Distinct from `ScreenInsetArea` (which avoids *device* hardware margins, not client UI). See `{baseDir}/references/ui-components.md` → InteractableArea.
125
+
**InteractableArea** — Wrapper that keeps children inside the renderer-reported *interactable area* — the part of the screen NOT covered by the client's own UI (minimap, chat window, platform overlays). Reads `UiCanvasInformation.interactableArea` and constrains children via absolute positioning; on the Unity desktop client the left ~25% of the screen is reserved, so children fill the remaining ~75%. **Prefer `screenInset: 'interactable'` on the renderer for a whole-UI application**; use the component for a single subtree, or when the renderer uses a different inset. Either form needs an explorer that reports the area: it works on desktop, and on mobile from client `1.12.1` onwards — older mobile clients report no margins and the inset silently does nothing. Like `ScreenInsetArea`, it owns `positionType`/`position` (values you pass are ignored) and falls back to zero insets (no-op) when unavailable. Import from `@dcl/sdk/react-ecs`; usage `<InteractableArea><MyHud /></InteractableArea>`. Distinct from `ScreenInsetArea` (which avoids *device* hardware margins, not client UI). See `{baseDir}/references/ui-components.md` → InteractableArea.
Copy file name to clipboardExpand all lines: build-ui/references/ui-components.md
+5-1Lines changed: 5 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -244,6 +244,8 @@ Wraps children so they stay inside the renderer-reported **interactable area**
244
244
245
245
**For a whole UI, prefer `screenInset: 'interactable'` on the renderer.** Use the component to inset a single subtree, or when the renderer sits in a different area.
246
246
247
+
⚠️ **Client support.** Either form needs an explorer that reports the area. It works on desktop, and on mobile from client version `1.12.1` onwards — older mobile clients report no margins, so the area falls back to the whole screen and the inset silently does nothing. Note that `1.12.1` is also the release that normalizes the `'device'` area between Android and iOS, so treat it as the floor for any inset-sensitive mobile layout.
Fields: `width`, `height`, `devicePixelRatio` (all numbers, in virtual/scaled units when a virtual size is set), plus `screenInsetArea` and `interactableArea` (`BorderRect` — `top`/`bottom`/`left`/`right` in canvas pixels). `devicePixelRatio` is a display-density hint, useful for picking a 1x/2x/3x texture.
375
+
Fields: `width`, `height`, `devicePixelRatio` (all numbers), plus `screenInsetArea` and `interactableArea` (`BorderRect` — `top`/`bottom`/`left`/`right`). `devicePixelRatio` is a display-density hint, useful for picking a 1x/2x/3x texture; it does not take part in UI layout.
376
+
377
+
⚠️ **`width` and `height` are RAW canvas pixels, not virtual/scaled units** — the SDK derives the UI scale factor from them (`Math.min(width / virtualWidth, height / virtualHeight)`), so they cannot already be scaled. The two `BorderRect`s are raw canvas pixels too. They are the right input for *decisions* (which layout, which texture resolution), not for computing sizes — the renderer already scales pixel values for you.
0 commit comments