Orbiters

Applicable XR devices
This guidance helps you build experiences for these types of XR devices.
XR Headsets
Wired XR Glasses

An Orbiter is a spatialized component that you can attach to a corresponding spatial panel or spatial layout component like a SpatialColumn, SpatialRow, or SpatialBox. An orbiter typically contains navigation and contextual action items related to the entity it's anchored to. For example, if you've created a spatial panel to display video content, you could add video playback controls inside an orbiter.

Figure 1.: Example of an orbiter.

Create an orbiter

As shown in the following example, call an orbiter inside the 2D layout in a SpatialPanel to wrap user controls like navigation. Doing so extracts them from your 2D layout and attaches them to the spatial panel according to your configuration.

Subspace {
    SpatialPanel(
        SubspaceModifier
            .height(824.dp)
            .width(1400.dp)
            .resizable()
            .movable(),
    ) {
        SpatialPanelContent()
        OrbiterExample()
    }
}

@Composable
fun OrbiterExample() {
    Orbiter(
        position = OrbiterPosition.BottomCenter(
            verticalEdgeAlignment = OrbiterPosition.EdgeAlignment.Outside,
            offset = DpVolumeOffset(y = 96.dp)
        ),
    ) {
        Surface(Modifier.clip(CircleShape)) {
            Row(
                Modifier
                    .background(color = Color.Black)
                    .height(100.dp)
                    .width(600.dp),
                horizontalArrangement = Arrangement.Center,
                verticalAlignment = Alignment.CenterVertically
            ) {
                Text(
                    text = "Orbiter",
                    color = Color.White,
                    fontSize = 50.sp
                )
            }
        }
    }
}

Key points about the code

  • Because orbiters are spatial UI components, the code can be reused in 2D or 3D layouts. In a 2D layout, your app renders only the content inside the orbiter and ignores the orbiter itself.
  • Check out our design guidance for more information on how to use and design orbiters.

Anchor orbiters to spatial panels and layouts

You can anchor an orbiter to a SpatialPanel and spatial layout components declared in Compose. This involves declaring an orbiter in a spatial layout of UI elements such as SpatialRow, SpatialColumn, or SpatialBox. The orbiter anchors to the parent that is nearest to where you've declared it.

The orbiter's behavior is determined by where you declare it:

  • In a 2D layout wrapped in a SpatialPanel (as shown in a preceding code snippet), the orbiter anchors to that SpatialPanel.
  • In a Subspace, the orbiter anchors to the nearest parent entity, which is the spatial layout the orbiter is declared in.

The following example shows how to anchor an orbiter to a spatial row:

Subspace {
    SpatialRow {
        Orbiter(
            position = OrbiterPosition.TopCenter(
                verticalEdgeAlignment = OrbiterPosition.EdgeAlignment.Outside,
                offset = DpVolumeOffset(y = 8.dp)
            ),
            shape = SpatialRoundedCornerShape(size = CornerSize(50))
        ) {
            Text(
                "Hello World!",
                style = MaterialTheme.typography.titleMedium,
                modifier = Modifier
                    .background(Color.White)
                    .padding(16.dp)
            )
        }
        SpatialPanel(
            SubspaceModifier
                .height(824.dp)
                .width(1400.dp)
        ) {
            Box(
                modifier = Modifier
                    .background(Color.Red)
            )
        }
        SpatialPanel(
            SubspaceModifier
                .height(824.dp)
                .width(1400.dp)
        ) {
            Box(
                modifier = Modifier
                    .background(Color.Blue)
            )
        }
    }
}

Key points about the code

  • When you declare an orbiter outside of a 2D layout, the orbiter anchors to its nearest parent entity. In this case, the orbiter anchors to the top of the SpatialRow it's declared in.
  • Spatial layouts such as SpatialRow, SpatialColumn, SpatialBox all have contentless entities associated with them. Therefore, an orbiter declared in a spatial layout anchors to that layout.