@dcl/react-ecs 7.25.1-31496802383.commit-d3168c9 → 7.25.1-31605440953.commit-08dff78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/InteractableArea/index.js +3 -2
- package/dist/components/ScreenInsetArea/index.js +3 -2
- package/dist/components/utils.js +23 -5
- package/dist/platform.d.ts +12 -0
- package/dist/platform.js +26 -0
- package/dist/system.d.ts +33 -3
- package/dist/system.js +134 -16
- package/package.json +3 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReactEcs } from '../../react-ecs';
|
|
2
2
|
import { UiEntity } from '../index';
|
|
3
|
-
import { getInteractableArea } from '../utils';
|
|
3
|
+
import { compensateInsetForUiScale, getInteractableArea } from '../utils';
|
|
4
4
|
/**
|
|
5
5
|
*
|
|
6
6
|
* @public
|
|
@@ -23,7 +23,8 @@ import { getInteractableArea } from '../utils';
|
|
|
23
23
|
*/
|
|
24
24
|
/* @__PURE__ */
|
|
25
25
|
export function InteractableArea(props) {
|
|
26
|
-
|
|
26
|
+
// Insets are canvas px; pre-divide so the parser's scale multiplication cancels out.
|
|
27
|
+
const { top, left, right, bottom } = compensateInsetForUiScale(getInteractableArea());
|
|
27
28
|
const { uiTransform, ...otherProps } = props;
|
|
28
29
|
return (ReactEcs.createElement(UiEntity, { ...otherProps, uiTransform: {
|
|
29
30
|
...uiTransform,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReactEcs } from '../../react-ecs';
|
|
2
2
|
import { UiEntity } from '../index';
|
|
3
|
-
import { getScreenInsetArea } from '../utils';
|
|
3
|
+
import { compensateInsetForUiScale, getScreenInsetArea } from '../utils';
|
|
4
4
|
/**
|
|
5
5
|
*
|
|
6
6
|
* @public
|
|
@@ -22,7 +22,8 @@ import { getScreenInsetArea } from '../utils';
|
|
|
22
22
|
*/
|
|
23
23
|
/* @__PURE__ */
|
|
24
24
|
export function ScreenInsetArea(props) {
|
|
25
|
-
|
|
25
|
+
// Insets are canvas px; pre-divide so the parser's scale multiplication cancels out.
|
|
26
|
+
const { top, left, right, bottom } = compensateInsetForUiScale(getScreenInsetArea());
|
|
26
27
|
const { uiTransform, ...otherProps } = props;
|
|
27
28
|
return (ReactEcs.createElement(UiEntity, { ...otherProps, uiTransform: {
|
|
28
29
|
...uiTransform,
|
package/dist/components/utils.js
CHANGED
|
@@ -38,8 +38,8 @@ export function getScaleAndUnit(scaleUnit) {
|
|
|
38
38
|
/**
|
|
39
39
|
* @internal
|
|
40
40
|
*/
|
|
41
|
-
export function scaleOnDim(scale, dim
|
|
42
|
-
return (dim / 100) *
|
|
41
|
+
export function scaleOnDim(scale, dim) {
|
|
42
|
+
return (dim / 100) * scale;
|
|
43
43
|
}
|
|
44
44
|
/**
|
|
45
45
|
* @internal
|
|
@@ -90,6 +90,21 @@ export function resetUiScaleFactor(owner) {
|
|
|
90
90
|
uiScaleOwner = undefined;
|
|
91
91
|
uiScaleFactor = 1;
|
|
92
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Divides an inset area by the current UI scale factor.
|
|
95
|
+
*
|
|
96
|
+
* Inset areas are reported by the renderer in canvas pixels, but raw pixel
|
|
97
|
+
* values in `uiTransform` props are multiplied by the UI scale factor when
|
|
98
|
+
* parsed. Pre-dividing cancels that multiplication out, so the values sent to
|
|
99
|
+
* the renderer stay in canvas pixels regardless of the virtual screen.
|
|
100
|
+
*
|
|
101
|
+
* @internal
|
|
102
|
+
*/
|
|
103
|
+
export function compensateInsetForUiScale(area) {
|
|
104
|
+
const scale = getUiScaleFactor();
|
|
105
|
+
const factor = scale > 0 ? scale : 1;
|
|
106
|
+
return { top: area.top / factor, left: area.left / factor, right: area.right / factor, bottom: area.bottom / factor };
|
|
107
|
+
}
|
|
93
108
|
/**
|
|
94
109
|
* @internal
|
|
95
110
|
*/
|
|
@@ -169,9 +184,12 @@ export function calcOnViewport(value, ctx = getScaleCtx()) {
|
|
|
169
184
|
const [scale, unit] = getScaleAndUnit(value);
|
|
170
185
|
if (!ctx)
|
|
171
186
|
return scale;
|
|
172
|
-
|
|
187
|
+
// `ctx.ratio` is intentionally not read: '1vw' is 1% of the canvas width by
|
|
188
|
+
// definition, exactly as in CSS. It stays on ScaleContext as an informational
|
|
189
|
+
// density hint for callers that need to pick an asset resolution.
|
|
190
|
+
const { height, width } = ctx;
|
|
173
191
|
if (unit === 'vh')
|
|
174
|
-
return scaleOnDim(scale, height
|
|
192
|
+
return scaleOnDim(scale, height);
|
|
175
193
|
// by default, we scale by 'vw' (width)
|
|
176
|
-
return scaleOnDim(scale, width
|
|
194
|
+
return scaleOnDim(scale, width);
|
|
177
195
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Injects the function used to detect whether the scene runs on a mobile
|
|
3
|
+
* platform. Called by `@dcl/sdk` with its `isMobile()` platform helper.
|
|
4
|
+
*/
|
|
5
|
+
export declare function setIsMobileProvider(provider: () => boolean): void;
|
|
6
|
+
/**
|
|
7
|
+
* Whether the scene is running on a mobile platform, according to the
|
|
8
|
+
* injected provider. Platform detection is asynchronous on the SDK side, so
|
|
9
|
+
* this may return false during the first ticks and flip to true once the
|
|
10
|
+
* explorer information arrives.
|
|
11
|
+
*/
|
|
12
|
+
export declare function isMobile(): boolean;
|
package/dist/platform.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform detection hook for the UI scale system.
|
|
3
|
+
*
|
|
4
|
+
* react-ecs stays independent of the scene runtime (`~system/*` modules), so
|
|
5
|
+
* it cannot ask the explorer which platform it runs on. Instead, the host SDK
|
|
6
|
+
* injects the check at module-load time (see `@dcl/sdk/react-ecs`). Until a
|
|
7
|
+
* provider is injected — or when none ever is — the platform is assumed to be
|
|
8
|
+
* non-mobile.
|
|
9
|
+
*/
|
|
10
|
+
let isMobileProvider = () => false;
|
|
11
|
+
/**
|
|
12
|
+
* Injects the function used to detect whether the scene runs on a mobile
|
|
13
|
+
* platform. Called by `@dcl/sdk` with its `isMobile()` platform helper.
|
|
14
|
+
*/
|
|
15
|
+
export function setIsMobileProvider(provider) {
|
|
16
|
+
isMobileProvider = provider;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Whether the scene is running on a mobile platform, according to the
|
|
20
|
+
* injected provider. Platform detection is asynchronous on the SDK side, so
|
|
21
|
+
* this may return false during the first ticks and flip to true once the
|
|
22
|
+
* explorer information arrives.
|
|
23
|
+
*/
|
|
24
|
+
export function isMobile() {
|
|
25
|
+
return isMobileProvider();
|
|
26
|
+
}
|
package/dist/system.d.ts
CHANGED
|
@@ -4,12 +4,29 @@ import type { ReactEcs } from './react-ecs';
|
|
|
4
4
|
* @public
|
|
5
5
|
*/
|
|
6
6
|
export type UiComponent = () => ReactEcs.JSX.ReactNode;
|
|
7
|
+
/**
|
|
8
|
+
* Screen area used to position a renderer's UI entities:
|
|
9
|
+
* - `'device'` (default): the device safe area (excludes notch, status bar,
|
|
10
|
+
* rounded corners), reported in `UiCanvasInformation.screenInsetArea`.
|
|
11
|
+
* - `'interactable'`: the area free of the Explorer's native HUD (minimap, chat, ...),
|
|
12
|
+
* reported in `UiCanvasInformation.interactableArea`.
|
|
13
|
+
* - `'none'`: the whole screen, with 0,0 at its top-left corner.
|
|
14
|
+
* @public
|
|
15
|
+
*/
|
|
16
|
+
export type UiScreenInset = 'device' | 'interactable' | 'none';
|
|
7
17
|
/**
|
|
8
18
|
* @public
|
|
9
19
|
*/
|
|
10
20
|
export type UiRendererOptions = {
|
|
11
|
-
virtualWidth
|
|
12
|
-
virtualHeight
|
|
21
|
+
virtualWidth?: number;
|
|
22
|
+
virtualHeight?: number;
|
|
23
|
+
/**
|
|
24
|
+
* Screen area the renderer's UI is positioned in. Defaults to `'device'`, so UI
|
|
25
|
+
* stays inside the device safe area unless the creator opts out with `'none'`.
|
|
26
|
+
* Each renderer honors its own value, so the main UI and additional renderers
|
|
27
|
+
* can use different insets simultaneously.
|
|
28
|
+
*/
|
|
29
|
+
screenInset?: UiScreenInset;
|
|
13
30
|
};
|
|
14
31
|
/**
|
|
15
32
|
* @public
|
|
@@ -21,6 +38,16 @@ export interface ReactBasedUiSystem {
|
|
|
21
38
|
destroy(): void;
|
|
22
39
|
/**
|
|
23
40
|
* Set the main UI renderer. Optional virtual size defines the global UI scale factor.
|
|
41
|
+
*
|
|
42
|
+
* When no virtual size is provided, a platform default is used: 1600x720 on
|
|
43
|
+
* mobile, 1920x1080 otherwise. Providing an invalid size disables the virtual
|
|
44
|
+
* screen (no UI scaling): either a value \<= 0, or only one of the two
|
|
45
|
+
* dimensions, which additionally logs a warning. On mobile, a provided 16:9
|
|
46
|
+
* virtual size is overridden to 1600x720 to fit phone screens.
|
|
47
|
+
*
|
|
48
|
+
* The optional `screenInset` selects the screen area the UI is positioned in
|
|
49
|
+
* (see {@link UiScreenInset}); it defaults to `'device'`. Pass `'none'` to
|
|
50
|
+
* place the UI over the whole screen.
|
|
24
51
|
*/
|
|
25
52
|
setUiRenderer(ui: UiComponent, options?: UiRendererOptions): void;
|
|
26
53
|
/**
|
|
@@ -35,7 +62,10 @@ export interface ReactBasedUiSystem {
|
|
|
35
62
|
* @param entity - The entity to associate with this UI renderer. When the entity is removed,
|
|
36
63
|
* the UI renderer is automatically cleaned up.
|
|
37
64
|
* @param ui - The UI component to render
|
|
38
|
-
* @param options - Optional virtual size used for UI scale factor when main UI has none
|
|
65
|
+
* @param options - Optional virtual size used for UI scale factor when main UI has none.
|
|
66
|
+
* Defaults and the mobile 16:9 override behave as in {@link ReactBasedUiSystem.setUiRenderer}.
|
|
67
|
+
* `screenInset` is honored per renderer, independently of the main UI's value,
|
|
68
|
+
* and defaults to `'device'` here too.
|
|
39
69
|
*/
|
|
40
70
|
addUiRenderer(entity: Entity, ui: UiComponent, options?: UiRendererOptions): void;
|
|
41
71
|
/**
|
package/dist/system.js
CHANGED
|
@@ -3,13 +3,49 @@ import * as ecsComponents from '@dcl/ecs/dist/components';
|
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { createReconciler } from './reconciler';
|
|
5
5
|
import { getUiScaleFactor, resetInteractableArea, resetScreenInsetArea, resetUiScaleFactor, setInteractableArea, setScreenInsetArea, setUiScaleFactor } from './components/utils';
|
|
6
|
+
import { InteractableArea, ScreenInsetArea } from './components';
|
|
7
|
+
import { isMobile } from './platform';
|
|
8
|
+
/**
|
|
9
|
+
* Default virtual screen size used on mobile platforms, and the size 16:9
|
|
10
|
+
* virtual screens are overridden to on mobile (phone screens are much wider
|
|
11
|
+
* than 16:9, so a 16:9 virtual canvas would letterbox the UI).
|
|
12
|
+
*/
|
|
13
|
+
const DEFAULT_MOBILE_VIRTUAL_SIZE = { virtualWidth: 1600, virtualHeight: 720 };
|
|
14
|
+
/**
|
|
15
|
+
* Default virtual screen size used on non-mobile platforms.
|
|
16
|
+
*/
|
|
17
|
+
const DEFAULT_VIRTUAL_SIZE = { virtualWidth: 1920, virtualHeight: 1080 };
|
|
18
|
+
/**
|
|
19
|
+
* Screen area a renderer uses when it doesn't pick one. UI defaults to the device
|
|
20
|
+
* safe area: drawing under a notch, a status bar or a rounded corner is something
|
|
21
|
+
* a creator should opt into, not the out-of-the-box behavior.
|
|
22
|
+
*/
|
|
23
|
+
const DEFAULT_SCREEN_INSET = 'device';
|
|
24
|
+
function hasVirtualSize(options) {
|
|
25
|
+
return !!options && (options.virtualWidth !== undefined || options.virtualHeight !== undefined);
|
|
26
|
+
}
|
|
27
|
+
function isValidVirtualSize(options) {
|
|
28
|
+
return !!options && (options.virtualWidth ?? 0) > 0 && (options.virtualHeight ?? 0) > 0;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Whether a provided size spells out one dimension but not the other. Both are
|
|
32
|
+
* optional in the type, so this is reachable. It is invalid either way — this only
|
|
33
|
+
* decides whether to warn, since a half-given size is a mistake while a value
|
|
34
|
+
* \<= 0 is the documented way to turn the virtual screen off.
|
|
35
|
+
*/
|
|
36
|
+
function isPartialVirtualSize(options) {
|
|
37
|
+
return (options.virtualWidth === undefined) !== (options.virtualHeight === undefined);
|
|
38
|
+
}
|
|
39
|
+
function is16by9(options) {
|
|
40
|
+
return options.virtualWidth * 9 === options.virtualHeight * 16;
|
|
41
|
+
}
|
|
6
42
|
/**
|
|
7
43
|
* @public
|
|
8
44
|
*/
|
|
9
45
|
export function createReactBasedUiSystem(engine, pointerSystem) {
|
|
10
46
|
const renderer = createReconciler(engine, pointerSystem);
|
|
11
47
|
let uiComponent = undefined;
|
|
12
|
-
let
|
|
48
|
+
let mainOptions = undefined;
|
|
13
49
|
const additionalRenderers = new Map();
|
|
14
50
|
const UiCanvasInformation = ecsComponents.UiCanvasInformation(engine);
|
|
15
51
|
// Unique owner to prevent other UI systems resetting this scale factor.
|
|
@@ -18,21 +54,92 @@ export function createReactBasedUiSystem(engine, pointerSystem) {
|
|
|
18
54
|
const screenInsetAreaOwner = Symbol('react-ecs-screen-inset-area');
|
|
19
55
|
// Unique owner for the interactable area module variable.
|
|
20
56
|
const interactableAreaOwner = Symbol('react-ecs-interactable-area');
|
|
57
|
+
// Last 16:9 size we already logged the mobile override for, so the log
|
|
58
|
+
// fires once per provided size instead of every tick. Tracked as raw numbers
|
|
59
|
+
// to avoid allocating a comparison string every tick.
|
|
60
|
+
let loggedMobileOverrideW = 0;
|
|
61
|
+
let loggedMobileOverrideH = 0;
|
|
62
|
+
// Same once-per-size guard for the incomplete-size warning. A partial size maps
|
|
63
|
+
// its missing dimension to 0, and the provided one can itself be 0, so -1 is the
|
|
64
|
+
// "nothing logged yet" sentinel — 0/0 is a reachable real value here.
|
|
65
|
+
let loggedPartialW = -1;
|
|
66
|
+
let loggedPartialH = -1;
|
|
21
67
|
function getActiveVirtualSize() {
|
|
22
68
|
// Main renderer options win; otherwise use the first additional renderer option.
|
|
23
|
-
|
|
24
|
-
|
|
69
|
+
// Options carrying no virtual dims (e.g. only a screen inset) are skipped so
|
|
70
|
+
// they don't count as a provided-but-invalid virtual size.
|
|
71
|
+
if (hasVirtualSize(mainOptions))
|
|
72
|
+
return mainOptions;
|
|
25
73
|
for (const entry of additionalRenderers.values()) {
|
|
26
|
-
if (entry.options)
|
|
74
|
+
if (hasVirtualSize(entry.options))
|
|
27
75
|
return entry.options;
|
|
28
76
|
}
|
|
29
77
|
return undefined;
|
|
30
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Resolves the virtual screen to scale the UI against, or `undefined` when
|
|
81
|
+
* the virtual screen is disabled.
|
|
82
|
+
*/
|
|
83
|
+
function resolveVirtualSize() {
|
|
84
|
+
const provided = getActiveVirtualSize();
|
|
85
|
+
const mobile = isMobile();
|
|
86
|
+
// No creator-provided size: fall back to the platform default.
|
|
87
|
+
if (!provided) {
|
|
88
|
+
return mobile ? DEFAULT_MOBILE_VIRTUAL_SIZE : DEFAULT_VIRTUAL_SIZE;
|
|
89
|
+
}
|
|
90
|
+
// An explicitly provided but invalid size disables the virtual screen — no UI
|
|
91
|
+
// scaling at all. That covers a value <= 0 (the deliberate opt-out) and a size
|
|
92
|
+
// that gives only one of its two dimensions.
|
|
93
|
+
if (!isValidVirtualSize(provided)) {
|
|
94
|
+
// A half-given size is a mistake rather than an opt-out, and disabling scaling
|
|
95
|
+
// is not what the creator was reaching for, so say so once per provided size.
|
|
96
|
+
// The <= 0 opt-out is documented and stays silent.
|
|
97
|
+
if (isPartialVirtualSize(provided)) {
|
|
98
|
+
const width = provided.virtualWidth ?? 0;
|
|
99
|
+
const height = provided.virtualHeight ?? 0;
|
|
100
|
+
if (loggedPartialW !== width || loggedPartialH !== height) {
|
|
101
|
+
loggedPartialW = width;
|
|
102
|
+
loggedPartialH = height;
|
|
103
|
+
console.log(`Incomplete virtual screen size (virtualWidth: ${provided.virtualWidth}, virtualHeight: ${provided.virtualHeight}): both dimensions are required, so the virtual screen is disabled and no UI scaling is applied.`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
// On mobile, 16:9 virtual screens don't fit phone aspect ratios — override them.
|
|
109
|
+
if (mobile && is16by9(provided)) {
|
|
110
|
+
if (loggedMobileOverrideW !== provided.virtualWidth || loggedMobileOverrideH !== provided.virtualHeight) {
|
|
111
|
+
loggedMobileOverrideW = provided.virtualWidth;
|
|
112
|
+
loggedMobileOverrideH = provided.virtualHeight;
|
|
113
|
+
console.log(`Mobile platform detected: overriding 16:9 virtual screen size ${provided.virtualWidth}x${provided.virtualHeight} with ${DEFAULT_MOBILE_VIRTUAL_SIZE.virtualWidth}x${DEFAULT_MOBILE_VIRTUAL_SIZE.virtualHeight}`);
|
|
114
|
+
}
|
|
115
|
+
return DEFAULT_MOBILE_VIRTUAL_SIZE;
|
|
116
|
+
}
|
|
117
|
+
return provided;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Wraps a renderer's component in a container positioned within the selected
|
|
121
|
+
* screen inset area. `'none'` adds no wrapper, leaving the UI on the whole
|
|
122
|
+
* screen. Applied per renderer, so each renderer can use a different inset.
|
|
123
|
+
*/
|
|
124
|
+
function wrapWithScreenInset(ui, inset, key) {
|
|
125
|
+
// An omitted inset is resolved to DEFAULT_SCREEN_INSET ('device') before the
|
|
126
|
+
// switch, so it lands on `case 'device'`. Only an explicit 'none' reaches the
|
|
127
|
+
// `default` clause below — the two are unrelated despite sharing a name.
|
|
128
|
+
switch (inset ?? DEFAULT_SCREEN_INSET) {
|
|
129
|
+
case 'device':
|
|
130
|
+
return React.createElement(ScreenInsetArea, { key }, React.createElement(ui));
|
|
131
|
+
case 'interactable':
|
|
132
|
+
return React.createElement(InteractableArea, { key }, React.createElement(ui));
|
|
133
|
+
// 'none' — the whole screen, no wrapper entity
|
|
134
|
+
default:
|
|
135
|
+
return React.createElement(ui, { key });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
31
138
|
function ReactBasedUiSystem() {
|
|
32
139
|
const components = [];
|
|
33
140
|
// Add main UI component
|
|
34
141
|
if (uiComponent) {
|
|
35
|
-
components.push(
|
|
142
|
+
components.push(wrapWithScreenInset(uiComponent, mainOptions?.screenInset, '__main__'));
|
|
36
143
|
}
|
|
37
144
|
const entitiesToRemove = [];
|
|
38
145
|
for (const [entity, entry] of additionalRenderers) {
|
|
@@ -41,7 +148,7 @@ export function createReactBasedUiSystem(engine, pointerSystem) {
|
|
|
41
148
|
entitiesToRemove.push(entity);
|
|
42
149
|
}
|
|
43
150
|
else {
|
|
44
|
-
components.push(
|
|
151
|
+
components.push(wrapWithScreenInset(entry.ui, entry.options?.screenInset, `__entity_${entity}__`));
|
|
45
152
|
}
|
|
46
153
|
}
|
|
47
154
|
// Entity-based cleanup
|
|
@@ -68,22 +175,33 @@ export function createReactBasedUiSystem(engine, pointerSystem) {
|
|
|
68
175
|
if (canvasInfo?.interactableArea) {
|
|
69
176
|
setInteractableArea(canvasInfo.interactableArea, interactableAreaOwner);
|
|
70
177
|
}
|
|
71
|
-
|
|
72
|
-
|
|
178
|
+
// The virtual screen (provided or defaulted) only applies while some
|
|
179
|
+
// renderer is registered; with no UI at all the scale factor is released.
|
|
180
|
+
if (uiComponent === undefined && additionalRenderers.size === 0) {
|
|
73
181
|
// Reset only if this system owns the scale factor.
|
|
74
182
|
resetUiScaleFactor(uiScaleFactorOwner);
|
|
75
183
|
return;
|
|
76
184
|
}
|
|
185
|
+
const activeVirtualSize = resolveVirtualSize();
|
|
186
|
+
if (!activeVirtualSize) {
|
|
187
|
+
// Virtual screen explicitly disabled by an invalid provided size.
|
|
188
|
+
resetUiScaleFactor(uiScaleFactorOwner);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
77
191
|
if (!canvasInfo)
|
|
78
192
|
return;
|
|
79
|
-
const { width, height
|
|
193
|
+
const { width, height } = canvasInfo;
|
|
80
194
|
const { virtualWidth, virtualHeight } = activeVirtualSize;
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
|
|
195
|
+
// The scale factor is the contain-fit of the design resolution inside the canvas,
|
|
196
|
+
// and nothing else.
|
|
197
|
+
//
|
|
198
|
+
// devicePixelRatio is deliberately absent. It is a density hint — "how many physical
|
|
199
|
+
// pixels per canvas unit", for picking a 1x/2x/3x asset — not a layout unit, the same
|
|
200
|
+
// role it has in CSS and React Native, where it is exposed but never enters layout.
|
|
201
|
+
// Dividing by it made UI size inversely proportional to a quantity the scene author
|
|
202
|
+
// does not control and that measures something different on every renderer: panel
|
|
203
|
+
// density on mobile, OS display scaling on web, display/window on native desktop.
|
|
204
|
+
const nextScale = Math.min(width / virtualWidth, height / virtualHeight);
|
|
87
205
|
if (Number.isFinite(nextScale) && nextScale !== getUiScaleFactor()) {
|
|
88
206
|
// Track ownership when updating to avoid cross-system conflicts.
|
|
89
207
|
setUiScaleFactor(nextScale, uiScaleFactorOwner);
|
|
@@ -104,7 +222,7 @@ export function createReactBasedUiSystem(engine, pointerSystem) {
|
|
|
104
222
|
},
|
|
105
223
|
setUiRenderer(ui, options) {
|
|
106
224
|
uiComponent = ui;
|
|
107
|
-
|
|
225
|
+
mainOptions = options;
|
|
108
226
|
},
|
|
109
227
|
addUiRenderer(entity, ui, options) {
|
|
110
228
|
additionalRenderers.set(entity, { ui, options });
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dcl/react-ecs",
|
|
3
3
|
"description": "Decentraland ECS",
|
|
4
|
-
"version": "7.25.1-
|
|
4
|
+
"version": "7.25.1-31605440953.commit-08dff78",
|
|
5
5
|
"author": "DCL",
|
|
6
6
|
"bugs": "https://github.com/decentraland/js-sdk-toolchain/issues",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@dcl/ecs": "7.25.1-
|
|
8
|
+
"@dcl/ecs": "7.25.1-31605440953.commit-08dff78",
|
|
9
9
|
"react": "^18.2.0",
|
|
10
10
|
"react-reconciler": "^0.29.0"
|
|
11
11
|
},
|
|
@@ -40,5 +40,5 @@
|
|
|
40
40
|
"tsconfig": "./tsconfig.json"
|
|
41
41
|
},
|
|
42
42
|
"types": "./dist/index.d.ts",
|
|
43
|
-
"commit": "
|
|
43
|
+
"commit": "08dff7864080ec5e4a06b533827c69799774a2f2"
|
|
44
44
|
}
|