Skip to main content
Version: 3.5.x

Mount & Workspace Transforms

Two transforms position the device in application space. Understanding the pipeline helps you pick the right one.

Coordinate pipeline

StageWhat it doesHow to set itPersistent?
BasisRemaps axes (e.g., Z-up → Y-up)session.configure.basisYes
Mount transformPhysical mounting offset of the device (arm position, rotation, scale)configure.mount or configure.presetYes
Workspace transformCamera / scene navigation driftcommands.set_transform or the Navigation moduleYes (sticky)

Mount transform

The mount describes where the device physically sits — its arm offset, orientation, and scale. It's set once (or when the user changes the physical setup) and rarely updated at runtime.

Presets (factory configurations)

Instead of computing the mount yourself, pick a named preset:

PresetOrigin placementArm facing
defaultsDevice baseForward (arm front)
arm_frontDevice baseForward
arm_front_centeredWorkspace centreForward
led_frontDevice baseLED side forward
led_front_centeredWorkspace centreLED side forward
customManual — set mount yourself

A preset sets the mount, basis, and workspace origin in one shot.

Setting the mount directly

{
"inverse3": [{
"device_id": "049D",
"configure": {
"mount": {
"transform": {
"position": { "x": 0.0, "y": 0.0, "z": 0.0 },
"rotation": { "x": 0.0, "y": 0.0, "z": 0.0, "w": 1.0 },
"scale": { "x": 1.0, "y": 1.0, "z": 1.0 }
}
}
}
}]
}
mount and preset are mutually exclusive

Sending both in the same message is ambiguous — the service rejects it. Choose one: a named preset (which sets the mount for you) or an explicit mount transform.

Command vs snapshot asymmetry

When sending a mount, wrap the transform: { "mount": { "transform": { … } } }. When reading a mount from the snapshot, it's flat: { "mount": { "position": …, "rotation": …, "scale": … } }. This is by design — commands use the unified command_data wrapper; snapshots serialize the core::transform directly.

Workspace transform

The workspace transform is a runtime drift applied on top of the mount. Its typical use case is scene navigation — panning, rotating, or zooming the application's view while the device stays physically in place.

Both mount and workspace transforms are persistent — the service remembers the last value you sent. The difference is purpose and performance:

  • Mount is designed to be set once and stay — it describes the physical setup and is optimised for infrequent updates.
  • Workspace transform is designed to be streamed at high frequency (e.g., every frame during camera navigation) — the internal pipeline is optimised for this update rate.
{
"inverse3": [{
"device_id": "049D",
"commands": {
"set_transform": {
"transform": {
"position": { "x": 1.0, "y": 0.0, "z": 0.0 },
"rotation": { "x": 0.0, "y": 0.0, "z": 0.0, "w": 1.0 },
"scale": { "x": 1.0, "y": 1.0, "z": 1.0 }
}
}
}
}]
}
Use the Navigation module for automated drift

If you need continuous locomotion (bubble navigation, rate-control drift), use the Navigation module instead of manually streaming set_transform every tick — it handles the physics, haptic feedback, and workspace bounding for you.