Register 2D panels
Updated: Oct 1, 2025
Using 2D panels requires two steps: registration and
spawning them in your scene. This page covers registration.
Panel registration creates a blueprint for your panel. It does not add the panel to the scene. To spawn a panel into your scene, add an Entity with a Panel component that references this blueprint. Learn more in
Spawn and remove 2D panels.
To register a panel, create a PanelRegistration object and configure it for your specific panel. Here is an example PanelRegistration configuration:
import com.meta.spatial.toolkit.PanelRegistration
...
// In your immersive activity, override registerPanels()
// and return a list of PanelRegistration objects
override fun registerPanels(): List<PanelRegistration> {
return listOf(
LayoutXMLPanelRegistration( /* registration info */ ),
ActivityPanelRegistration( /* registration info */ ),
)
}
Note: The samples in this documentation are using v0.8.0. If you are using an earlier version, see the advanced PanelCreator section below for details on previous APIs.
Register a panel dynamically by calling the registerPanel() API in your immersive activity:
registerPanel(ViewPanelRegistration( /* registration info */ ))
Panel registration involves a few critical elements:
- Defining an ID for the panel.
- Determining a UI to render to the panel.
- Configuring the panel.
- Hooking-up behavior to layout within the panel.
Define an ID for the panel
Pass a registrationId in the constructor for any PanelRegistration. This is the ID of your blueprint. Use this ID to spawn the panel into the scene using the Panel component on an Entity.
For example:
LayoutXMLPanelRegistration(
R.id.my_panel,
...
)
This registers a panel using R.id.my_panel. You define resource IDs in the res/values/ids.xml file of your application:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="my_panel" type="id"/>
</resources>
The ID can be any integer. Using a resource ID (R.id.{id here}) is recommended for type safety and to avoid ID conflicts.
Create multiple Entities in your scene with the same panel UI by creating multiple Panel Entities that point to the same PanelRegistration ID.
Determine a UI to render to the panel
The UI you render to your panel can be defined in a few ways:
- Layout XML: Use
LayoutXMLPanelRegistration to define panel UI using layout XML. - View: Use
ViewPanelRegistration to define panel UI using a View at runtime. - Activity: Use
ActivityPanelRegistration to define panel UI using an Activity. - Intent: Use
IntentPanelRegistration to define panel UI using an Intent (allowing you to pass information along to your inflated Activity). - Media: Take a look at Media panels for more information on registering media panels.
- Jetpack Compose: Take a look at Jetpack Compose for more information on registering Jetpack Compose panels.
If you are new to Spatial SDK, start with Jetpack Compose.
Running many activities simultaneously reduces performance. Activity-based panels (activity/intent) have higher performance costs than view-based panels (layout xml/runtime).
Panels are configured using the
settingsCreator callback. For UI panels this means defining a
UIPanelSettings object. (For media panels please see
Media panels for information on additional
PanelSettings types.)
The UIPanelSettings object configures the panel’s size, position, and other properties. It has these settable options:
class UIPanelSettings(
val shape: UIPanelShapeOptions,
val display: UIPanelDisplayOptions,
val rendering: UIPanelRenderOptions,
val style: PanelStyleOptions,
val input: PanelInputOptions,
)
shape: How the panel looks in 3d. This can be a rectangle or a cylinder.display: Set the resolution of the panel content.rendering: Configure how the panel is rendered including whether it uses a mesh or a layer.style: Set the Android theme for the panel content.input: Configure the input behavior of the panel.
Here is an example of a panel registration with a fully configured UIPanelSettings object:
LayoutXMLPanelRegistration(
R.id.my_panel,
layoutIdCreator = { R.layout.my_layout },
settingsCreator = {
UIPanelSettings(
shape = QuadShapeOptions(width = 0.8f, height = 0.6f),
display = DpDisplayOptions(width = 400f, height = 300f),
rendering = UIPanelRenderOptions(),
style = PanelStyleOptions(themeResourceId = R.style.PanelAppThemeTransparent),
input = PanelInputOptions(),
)
})
Customize the inflated panel using information about the Entity that is inflating the panel. The following example defines a settingsCreator that changes the panel width based on a custom component.
settingsCreator = { ent: Entity ->
// Use a custom component to attach data to the Entity
// which is used to change the size of the created panel
val myComponent = ent.getComponent<MyCustomPanelSizeComponent>()
UIPanelSettings(
shape = QuadShapeOptions(width = myComponent.width, height = 1.5f),
display = ScreenFractionDisplayOptions(),
)
},
Hook-up behavior to UI within your panel (Layout XML/view)
When defining a Layout XML or view-based panel, add behavior (like responding to button presses) using the panelSetupWithRootView argument in the constructors for LayoutXMLPanelRegistration and ViewPanelRegistration.
Here is an example of a panel defined by Layout XML that responds to button presses:
LayoutXMLPanelRegistration(
registrationId = R.id.my_panel
layoutIdCreator = { R.layout.my_layout },
settingsCreator = {
UIPanelSettings(shape = QuadShapeOptions(width = 1.0f, height = 1.5f))
},
panelSetupWithRootView = {
rootView: View,
_panelSceneObject: PanelSceneObject,
_entity: Entity ->
// Set up a button click listener
rootView.findViewById<Button>(R.id.btn_intent_panel)?.setOnClickListener {
buttonPushed()
}
}
)
Advanced panel registration
Advanced Usage: This section is for developers who need to modify panel settings that aren’t covered by the standard PanelSettings APIs. Most developers won’t need this.
If you need to customize panel behavior beyond what the PanelSettings APIs provide, use PanelCreator to directly create a PanelSceneObject. A PanelSceneObject is the underlying runtime object that manages the panel. Configure it using PanelConfigOptions.
Behind the scenes, the PanelSettings APIs such as UIPanelSettings are convenience functions for constructing PanelConfigOptions. Start with UIPanelSettings to generate the basic configuration, then customize as needed. Here is an example:
import com.meta.spatial.toolkit.PanelCreator
import com.meta.spatial.toolkit.PanelRegistration
PanelCreator(
registrationId = R.id.custom_panel,
panelCreator = { entity ->
// Start with Panel Settings for basic configuration
val baseSettings = UIPanelSettings(
shape = QuadShapeOptions(width = 2f, height = 1.5f),
display = DpDisplayOptions(width = 800f, height = 600f)
)
// Convert to PanelConfigOptions and customize further
val options = baseSettings.toPanelConfigOptions().apply {
// Access properties not available through UIPanelSettings
// Here are a few examples of the many things you can set
mips = 8 // Custom mip levels
effectShader = "data/shaders/custom/gammaCorrection.frag" // Custom effect shader
// Custom mesh creator for specialized geometry
sceneMeshCreator = { texture ->
// Create custom mesh geometry
createCustomPanelMesh(texture, entity)
}
}
// Create the panel with custom options
PanelSceneObject(
scene,
spatialContext,
R.layout.my_custom_layout,
entity,
options
)
}
)