Skip to main content
Version: 3.5.x

Navigation

The Navigation module lets an Inverse3 cursor move the application's workspace — sometimes called rate-control locomotion or "gamepad-like drift". Instead of the cursor hitting a hard wall at the edge of the physical workspace, it enters a soft shell where its distance from a virtual centre is mapped to a velocity that slides the whole workspace. The further the cursor pushes, the faster the scene scrolls.

The primary (and currently only) behaviour is Bubble Navigation. The bubble shape is defined using an SDF primitive — see What is an SDF? for the concept.


Bubble Navigation — concept

A virtual bubble is anchored around a centre point in the device's mount space. The cursor experiences three concentric zones:

┌──────────────────────────────────────────┐
│ WALL ZONE │ cursor beyond outer shell
│ ┌────────────────────────────────────┐ │
│ │ VELOCITY ZONE │ │ soft shell → scene moves
│ │ ┌──────────────────────────────┐ │ │
│ │ │ DEAD ZONE (inside) │ │ │ no scene movement
│ │ │ │ │ │
│ │ │ ● centre │ │ │
│ │ │ │ │ │
│ │ └──────────────────────────────┘ │ │
│ │ bubble surface │ │
│ └────────────────────────────────────┘ │
│ outer boundary │
└──────────────────────────────────────────┘
ZoneCursor positionBehaviour
Dead zoneInside the bubbleNo navigation. Light damping. You can manipulate the scene freely.
Velocity zoneBetween the surface and the outer boundaryDistance → velocity curve moves the workspace in the cursor's direction.
Wall zonePast the outer boundaryA hard spring pushes the cursor back in and navigation velocity saturates.

A spring-damper haptic force is applied across all three zones — you feel the surface, the drift shell, and the outer wall.


Quick start — enable bubble navigation

Navigation is a persistent, one-shot configuration — send it once and it stays active until you explicitly stop it, restart the service, or close the session.

Start (minimal — spherical bubble with default sizing)

{
"inverse3": [
{
"device_id": "04C3",
"configure": {
"navigation": { "mode": "bubble" }
}
}
]
}

Stop

{
"inverse3": [
{
"device_id": "04C3",
"configure": {
"navigation": { "mode": "disabled" }
}
}
]
}

Other HTTP routes

MethodPathPurpose
GET/{type}/{id}/config/navigation?session=<expr>Current navigation config + state
POST/{type}/{id}/config/navigation?session=<expr>Start or update navigation
DELETE/{type}/{id}/config/navigation?session=<expr>Stop navigation

Bubble shape catalogue

The bubble's dead zone is described by a signed-distance-function (SDF) shape. Different shapes give different navigation feels — a sphere for isotropic drift, an ellipsoid or box to favour certain axes, a capsule for corridors.

Sphere (default)

{
"shape": {
"primitive": "sphere",
"parameters": { "r": 0.05 }
}
}

Ellipsoid — wider in X/Z than Y

Use when horizontal drift should feel looser than vertical:

{
"shape": {
"primitive": "ellipsoid",
"parameters": { "a": { "x": 0.06, "y": 0.03, "z": 0.06 } }
}
}

Rounded box — rectangular dead zone with soft corners

{
"shape": {
"primitive": "rounded_box",
"parameters": { "b": { "x": 0.04, "y": 0.02, "z": 0.04 }, "r": 0.008 }
}
}

Capsule — elongated corridor

Two end points a/b plus a radius r:

{
"shape": {
"primitive": "capsule",
"parameters": {
"a": { "x": 0.0, "y": -0.03, "z": 0.0 },
"b": { "x": 0.0, "y": 0.03, "z": 0.0 },
"r": 0.04
}
}
}

Full example with custom sizing and motion feel:

{
"inverse3": [
{
"device_id": "04C3",
"configure": {
"navigation": {
"mode": "bubble",
"bubble": {
"shape": {
"primitive": "ellipsoid",
"parameters": { "a": { "x": 0.06, "y": 0.03, "z": 0.06 } }
},
"velocity_zone_width": 0.025,
"max_velocity": 1.0,
"velocity_ease": "quadratic_in",
"workspace_bounded": true
}
}
}
}
]
}

Velocity curve

The velocity-zone distance is mapped through an easing curve before being turned into workspace velocity. Pick the easing that matches how you want the scene to accelerate as the user pushes further into the shell.

velocity_easeFeelWhen to use
linearConstant rampPredictable, good default
quadratic_inSlow start, faster pushPrecise near the surface, fast long travel
cubic_inVery slow startVery precise, long travel ramps up
sine_outSmooth fast start, plateaus near outerResponsive, caps gently
quadratic_outFast at entry, comfortable long-distanceFast nudge, comfortable cruising
{ "velocity_ease": "quadratic_in", "max_velocity": 1.5 }

Centre modes

The bubble's centre can follow the cursor, snap to it, or stay fixed in mount space.

center_modeBehaviourUse case
auto_follow (default)Drifts slowly toward the cursor at center_drift_speed when the cursor is inside the bubbleGeneral-purpose navigation — the centre "relaxes" back under the cursor between pushes
fixedCentre never moves automaticallyAnchored navigation around a specific reference point
track_cursorCentre snaps to the cursor each tickTeleport-style movement — the cursor is always at the bubble centre
{ "center_mode": "fixed" }

In every mode: if the cursor pushes past the outer boundary, the centre tracks the cursor to keep the bubble around it and prevent the cursor from escaping.


Workspace bounding

Most devices have a limited physical reach. When workspace_bounded is set, the bubble centre is kept inside the device's physical workspace so the resulting navigation doesn't drive the cursor outside of its reachable volume.

{ "workspace_bounded": true }

If the initial centre lies outside the workspace, the module eases it back inside over time (workspace_transition_speed / workspace_transition_ease) instead of snapping — avoiding a haptic jerk on start.


Avatar boundaries

When avatar_boundary_enabled is set, the final avatar world position (workspace + cursor) is clamped inside an arbitrary SDF shape. Useful for containing the user inside a room, corridor, vehicle cockpit, etc., without scripting per-axis clamps.

{
"avatar_boundary_enabled": true,
"avatar_boundary": {
"primitive": "box",
"parameters": { "b": { "x": 5.0, "y": 3.0, "z": 5.0 } }
}
}

The avatar_boundary shape accepts the same primitives as the bubble shape (sphere, ellipsoid, rounded_box, capsule, box, ...).


Collision response

The bubble reacts to external cursor forces exceeding collision_threshold:

  • The velocity zone temporarily inflates (up to collision_inflate_scale times velocity_zone_width) to give the user more room to manoeuvre around the obstacle.
  • With stop_at_collision, the bubble centre refuses to drift in the direction of the collision force, preventing the user from dragging the workspace into a hard wall.
{ "stop_at_collision": true, "collision_threshold": 0.5, "collision_inflate_scale": 2.0 }

Parameters reference

Most commonly tuned

ParameterDefaultDescription
shape{sphere, r=0.05}SDF shape defining the dead zone
velocity_zone_width0.03 mThickness of the rate-control shell
max_velocity1.0 m/sMaximum navigation velocity
velocity_ease"linear"Distance → velocity easing curve
center_mode"auto_follow"How the centre tracks the cursor
workspace_boundedfalseClamp centre to device physical workspace

Full parameter list

FieldTypeDefaultDescription
centervec3(0,0,0)Initial bubble centre in mount space
shapeshape{sphere, r=0.05}Dead-zone SDF shape
velocity_zone_widthfloat0.03Width of the rate-control shell (m)
max_velocityfloat1.0Max navigation velocity (m/s)
velocity_easestring"linear"Distance→velocity easing
reset_velocity_on_entrybooltrueZero the accumulated speed when the cursor re-enters the velocity zone
bump_widthfloat0.003Tactile bump at the surface (m)
bump_stiffnessfloat500.0Surface bump spring constant
spring_innerfloat4.0Spring at the bubble centre
spring_surfacefloat7.0Spring at the surface
spring_outerfloat12.0Spring at the outer boundary
wall_stiffnessfloat700.0Hard-wall spring past the outer boundary
damping_innerfloat0.2Damping at the centre
damping_surfacefloat0.7Damping at the surface
damping_outerfloat5.0Damping at the outer boundary
rotation_enabledboolfalseApply the workspace rotation to the navigation direction
scale_enabledboolfalseApply the workspace scale to the navigation velocity
center_modeenum"auto_follow""auto_follow" / "fixed" / "track_cursor"
center_drift_speedfloat0.03Drift speed in auto_follow mode (m/s)
workspace_boundedboolfalseClamp bubble centre to the device workspace
workspace_transition_speedfloat1.2Speed of the initial clamp transition
workspace_transition_easestring"quadratic_in_out"Easing of the initial clamp transition
stop_at_collisionboolfalseBlock navigation in the collision direction
collision_thresholdfloat0.001External force threshold to detect a collision (N)
collision_inflate_scalefloat2.0Multiplier for the velocity-zone width during a collision
avatar_boundary_enabledboolfalseActivate avatar-boundary clamping
avatar_boundaryshape{sphere, r=0.1}SDF shape for the avatar-position constraint

Validation rules

  • velocity_zone_width > 0
  • 0 ≤ bump_width < velocity_zone_width
  • max_velocity > 0
  • spring_inner ≤ spring_surface ≤ spring_outer
  • damping_inner ≤ damping_surface ≤ damping_outer
  • collision_threshold > 0, collision_inflate_scale ≥ 1.0
  • All speed values are non-negative

A POST or configure.navigation with invalid parameters is rejected and an invalid-value event is emitted; the previous configuration remains active.


Events

Event nameFired when
navigation-startedNavigation is activated on a device
navigation-updatedNavigation config is updated while already active
navigation-stoppedNavigation is stopped (explicit disable, DELETE, or session close)
invalid-valueA navigation config is rejected by validation

Known limitations

  • Non-uniform scale + rotation: when both rotation_enabled and scale_enabled are on, the velocity direction is slightly inaccurate — rotation is not applied to the scale axes.
  • Workspace-bounding transition: the smooth clamp-back transition only runs at initialisation. If the bubble centre drifts outside the workspace during normal use, the clamp snaps without easing.
  • Per-device size scaling: bubble sizes (radius, zone width) are not scaled by the device's physical scale factor — Minverse and Inverse3 use the same absolute sizes, which may feel different on each.