Coordinate Systems
MultiSet VPS returns poses in left-handed Y-up (Unity, the default) or right-handed Y-up (ARKit, ARCore, WebXR) coordinates via the isRightHanded flag.
Overview
Every successful localization returns a 6-DoF pose: a position (x, y, z) in meters and a rotation quaternion (x, y, z, w), both expressed in the map's coordinate space.
MultiSet supports two coordinate conventions for that pose, and both are Y-up:
Left-handed, Y-up (LHS)
isRightHanded: false (default)
Unity, MultiSet Quest SDK, MultiSet App
Right-handed, Y-up (RHS)
isRightHanded: true
ARKit (iOS), ARCore (Android), WebXR, Three.js, OpenGL
LHS is the map's native frame: it is how poses are stored internally, and it is what you get when the flag is omitted. Setting isRightHanded: true asks the server to convert the pose before returning it.
The two frames share the same origin, the same up axis, and the same scale. They differ by a mirror across the YZ plane: the X axis is negated. The same physical camera pose therefore has identical y and z values in both, with an opposite sign on x.
Which convention should I use?
Unity SDK
Left-handed, Y-up
Nothing. The SDK uses the default and places content directly.
MultiSet Quest SDK
Left-handed, Y-up
Nothing. Unity based, so the default applies.
iOS native (ARKit)
Right-handed, Y-up
Send isRightHanded: true
Android native (ARCore)
Right-handed, Y-up
Send isRightHanded: true
WebXR SDK (Three.js / Needle)
Right-handed, Y-up
Send isRightHanded: true (the WebXR SDK already defaults to it)
Custom REST integration
Your choice
Pick the one that matches your renderer or engine
Setting the flag
isRightHanded is optional on every query endpoint and defaults to false.
POST /vps/map/query
JSON
"isRightHanded": true
POST /vps/map/query-form
form-data
isRightHanded=true (string)
POST /vps/map/multi-image-query
form-data
isRightHanded=true (string)
POST /vps/object/query
form-data
isRightHanded=true (string)
On the form-data endpoints every field is a string, so send the literal text true or false. Omit the field entirely to get the left-handed default.
Example: the same query in both conventions
Left-handed (default)
Drop this straight into a Unity Transform:
Right-handed
Drop this straight into a Three.js object:
The same request as form-data:
Converting a pose yourself
If you receive a pose in one convention and need the other, mirror it across the YZ plane: negate position.x, negate rotation.y and rotation.z, and leave everything else alone. The operation is its own inverse, so the same function converts in both directions.
What isRightHanded does not change
The flag governs the pose the API returns. Several other values are always expressed in the map's native left-handed frame, no matter what you set:
GeoPose response
Unaffected
The server un-mirrors the pose before georeferencing, so GeoPose is the same either way
The most common mistake is passing a right-handed hintPosition from a previous RHS localization result. The hint then points to the mirrored side of the map, so the search filter looks in the wrong place and localization fails or returns a poor pose. Negate x first.
Multi frame query
The multi frame query also takes an optional per-frame trackingPose from your local SLAM session. When you send them they are fused with the per-image estimates, so use the same convention you declared with isRightHanded: RHS tracking poses with isRightHanded: true, LHS tracking poses with the default. Send a pose for every frame or for none, because a partial set is treated as if you had sent none, see Tracking poses are optional. The trackingPose echoed back in the response is your input, returned unchanged, and is absent when you query without poses.
Object Tracking query
Object Tracking uses the same flag. It applies to the detected object's pose in the camera frame: LHS by default, RHS when isRightHanded: true.
Last updated
Was this helpful?

