decentraland / decentraland/unity-explorer
PrimaryPointerInfo screenCoordinates/screenDelta use bottom-left Y-up instead of top-left Y-down
- Dominant language
- C#
- Stars
- 23
- Forks
- 17
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 107
Description
## Summary
`PrimaryPointerInfo.screenCoordinates` and `screenDelta` are reported with a **bottom-left origin / Y up** (Unity's native screen space). Bevy and Godot report **top-left origin / Y down**, which is also the coordinate space of `UiTransform` / `UiCanvasInformation`. Scenes that compare the pointer against UI rects, or feed `screenDelta` into a `VirtualCamera` look, get a vertically mirrored cursor and inverted pitch on Unity only.
## Where
`Explorer/Assets/DCL/SDKComponents/PrimaryPointerInfo/Systems/PrimaryPointerInfoSystem.cs` — `UpdatePointerInfo()` writes `inputPoint.ReadValue()` (Unity screen space, Y up) and the accumulated `Camera.Delta` straight into `ScreenCoordinates` / `ScreenDelta`.
For comparison:
- Bevy: `crates/scene_runner/src/update_scene/pointer_lock.rs` uses `Window::cursor_position()` (top-left, Y down) and the mouse-motion delta (Y down).
- Godot: `lib/src/scene_runner/scene_manager.rs` uses the viewport mouse position (top-left, Y down) and its frame difference.
The [SDK docs](https://docs.decentraland.org/creator/development-guide/sdk7/system-based-events/) specify a top-left origin with Y increasing downward, matching `UiTransform`. The proto comment only says "screen space (pixels)", so documenting the convention there too would help. Suggested fix: `y = Screen.height - y` for the position and negate `delta.y`.
This was reported for `screenCoordinates` in #8757 (closed by the stale bot, not fixed); this issue adds the `screenDelta` half and a repro scene.
## How to validate
Minimal SDK7 scene: a 40x40 square follows the pointer using `screenCoordinates` in UI canvas space, and the log prints the delta sign while the pointer is locked.
```ts
import { engine, PrimaryPointerInfo, UiCanvasInformation, PointerLock } from '@dcl/sdk/ecs'
import ReactEcs, { ReactEcsRenderer, UiEntity } from '@dcl/sdk/react-ecs'
import { Color4 } from '@dcl/sdk/math'
export function main() {
ReactEcsRenderer.setUiRenderer(() => {
const cursor = PrimaryPointerInfo.getOrNull(engine.RootEntity)?.screenCoordinates
const canvas = UiCanvasInformation.getOrNull(engine.RootEntity)
if (!cursor || !canvas) return null
return (
)
})
engine.addSystem(() => {
if (!PointerLock.getOrNull(engine.CameraEntity)?.isPointerLocked) return
const delta = PrimaryPointerInfo.getOrNull(engine.RootEntity)?.screenDelta
if (delta && Math.abs(delta.y) > 2) console.log(delta.y > 0 ? 'delta.y > 0' : 'delta.y < 0')
})
}
```
Expected (Bevy, Godot): the red square sits under the cursor; moving the mouse **down** logs `delta.y > 0`.
Actual (Unity): the square is mirrored vertically (top of screen when the cursor is at the bottom); moving the mouse **down** logs `delta.y < 0`.
Contributor guide
Research direction
Start in Explorer/Assets/DCL/SDKComponents/PrimaryPointerInfo/Systems/PrimaryPointerInfoSystem.cs at UpdatePointerInfo(), where inputPoint and Camera.Delta are assigned to ScreenCoordinates and ScreenDelta. Validate with the minimal SDK7 repro scene: the red square should stay under the cursor, and moving the mouse down should log a positive delta.y as in Bevy and Godot.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp, unity
- Domain
- game-dev
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 84/100