This chapter teaches you how to create immersive spatial user interfaces using pmndrs/uikit, specifically UIKitML, the IWSDK spatial UI system.
What You’ll Learn
By the end of this chapter, you’ll be able to:
Understand spatial UI design principles.
Create UI layouts using UIKitML markup.
Position and scale interfaces in 3D space.
Handle user interactions with spatial UI elements.
Implement common UI patterns for WebXR.
Spatial UI Principles
Great spatial interfaces follow these principles:
World-scale: UI elements have a physical presence in 3D space.
Natural interaction: Use pointing, grabbing, and gestures.
Readable at distance: Text and icons scale appropriately.
Contextual placement: UI appears near relevant objects.
Comfortable viewing: Positioned to avoid neck strain.
Introduction to Building Spatial User Interfaces in IWSDK
HTML is unavailable in WebXR, and placing user interface elements by hand takes time. IWSDK uses pmndrs/uikit, a GPU-accelerated UI rendering system. Its API is aligned with HTML and CSS. IWSDK also uses the UIKitML language. UIKitML provides HTML-like syntax, including CSS classes. This integration lets developers reuse their HTML knowledge to build GPU-accelerated WebXR interfaces. IWSDK also uses two pre-built component collections from the uikit project: the Default Kit (based on shadcn/ui) and the Horizon Kit (based on the Reality Labs Design System).
Key Features
Declarative markup: Describe UI structure, not implementation.
3D layout system: Flexbox-like layouts in 3D space.
Component Kits: Pre-built buttons, panels, and sliders.
Event system: Handle clicks, hovers, and other interactions.
Theming support: Consistent styling across your application.
Basic Syntax
UIKitML uses HTML-style markup with CSS properties for styling and layout:
IWSDK includes a Vite plugin that compiles UIKitML files:
// vite.config.js
import { defineConfig } from 'vite';
import { compileUIKit } from '@iwsdk/vite-plugin-uikitml';
export default defineConfig({
plugins: [
compileUIKit({
sourceDir: 'ui', // Directory containing .uikitml files
outputDir: 'public/ui', // Where compiled .json files are written
verbose: true, // Enable build logging
}),
],
});
Creating Your First UIKitML File
Create src/ui/main-menu.uikitml and insert the following content, which uses the Panel, Button, ButtonIcon, and LoginIcon components from the Horizon Kit to design a panel with a button:
Component kits provide pre-built UI components like buttons, panels, inputs, and icons. IWSDK supports multiple kits that can be combined in your application.
Available Component Kits
@pmndrs/uikit-horizon - Reality Labs design system (buttons, panels, inputs).
@pmndrs/uikit-lucide - Icon library with 1000+ icons.
@pmndrs/uikit-default - Default kit based on the shadcn/ui design system.
Basic Kit Configuration
Configure kits in the spatialUI feature when creating your world:
import * as horizonKit from '@pmndrs/uikit-horizon';
World.create(document.getElementById('scene-container'), {
features: {
spatialUI: {
kits: [horizonKit],
},
},
});
Combining Multiple Kits
You can use components from multiple kits by passing them as an array:
import * as horizonKit from '@pmndrs/uikit-horizon';
import * as defaultKit from '@pmndrs/uikit-default';
World.create(document.getElementById('scene-container'), {
features: {
spatialUI: {
kits: [horizonKit, defaultKit],
},
},
});
Optimizing Bundle Size with Selective Imports
For large icon libraries like @pmndrs/uikit-lucide (which contains over 1000 icons), importing the entire package can significantly increase your bundle size. Instead, import only the icons you need:
import * as horizonKit from '@pmndrs/uikit-horizon';
import {
LogInIcon,
RectangleGogglesIcon,
SettingsIcon,
} from '@pmndrs/uikit-lucide';
World.create(document.getElementById('scene-container'), {
features: {
spatialUI: {
kits: [
horizonKit,
{ LogInIcon, RectangleGogglesIcon, SettingsIcon }, // Only these icons
],
},
},
});
This technique works with any kit component. Import what you need, and pass it as an object in the kits array.
Color Scheme and Theming
UIKitML supports automatic light and dark mode theming that can follow system preferences or be explicitly set.
Configuring Color Scheme
Set the preferred color scheme when creating your world:
import { ColorSchemeType } from '@iwsdk/core';
World.create(document.getElementById('scene-container'), {
features: {
spatialUI: {
preferredColorScheme: ColorSchemeType.Dark, // Force dark mode
},
},
});
The UI automatically updates when the color scheme changes, with no additional code needed.
Overview of Properties and Features Available for Building Spatial User Interfaces
When authoring a User Interface with IWSDK, developers can use almost all the features they know and love from HTML.
The following section shows all the available element types and styling methods for designing Spatial User Interfaces.
Element Types
Container Elements
Most HTML elements become containers that can hold children and text.