Develop and iterate on IWSDK UI panels efficiently. Use when working on PanelUI components, debugging UI layout, or improving UI design in IWSDK applications.
Install
npx skillscat add facebook/immersive-web-sdk/iwsdk-ui-panel Install via the SkillsCat registry.
IWSDK UI Panel Development Workflow
This skill teaches the efficient workflow for developing UI panels in IWSDK applications using temporary ScreenSpace positioning and backdrop techniques.
Quick Iteration Workflow
When working on a UI panel, follow these steps for rapid iteration:
1. Add Temporary ScreenSpace Component
Temporarily add the ScreenSpace component to your PanelUI entity to make it fill the 2D screen during development:
import { ScreenSpace } from '@iwsdk/core';
world
.createTransformEntity(panelHolder)
.addComponent(PanelUI, {
config: '/ui/your-panel.json',
maxWidth: 1.0,
maxHeight: 0.5,
})
.addComponent(ScreenSpace, {
width: '90vw', // Fill 90% of viewport width
height: '90vh', // Fill 90% of viewport height
top: '5vh', // Center with 5% margins
left: '5vw',
});Important: This is temporary for development only. Remove before production.
2. Create a Clean Backdrop
Create a solid color backdrop far from your gameplay area for clean UI visibility:
const backdrop = new Mesh(
new BoxGeometry(20, 20, 0.1),
new MeshBasicMaterial({ color: 0x1a1a2e }),
);
backdrop.position.set(0, 0, -50); // Far from gameplay
scene.add(backdrop);3. Position Camera Close to Backdrop
Move the camera very close to the backdrop (within 0.5m) to eliminate background distractions:
// Position camera very close to backdrop for clean UI development
camera.position.set(0, 0, -49.5); // Just 0.5m from backdrop at z=-50
camera.lookAt(0, 0, -50);Why close? The backdrop must fill the entire field of view to block out the 3D scene. Being far away (50m) won't work - you'll still see the environment around the edges.
4. Iterate with Screenshots
Now you can rapidly iterate on your UI:
- Make changes to your
.uikitmlfile - Take a screenshot to see the result against a clean backdrop
- The UI fills most of the screen, making it easy to see details like:
- Border colors and thickness
- Padding and spacing
- Text alignment and sizing
- Color contrast
- Overall layout
The ScreenSpace component makes the panel "follow" the camera, so it appears as a 2D overlay on your backdrop.
5. Test in VR
When you enter VR mode:
- The ScreenSpace component automatically detaches the panel from the camera
- The panel returns to its original 3D world space position
- Your gameplay is unaffected
This dual-mode behavior is handled automatically by the ScreenSpaceUISystem.
Understanding UIKit Size Signals
UIKit components expose size information through signals. Log these to debug layout issues:
const document = PanelDocument.data.document[entity.index];
console.log('computedSize:', document.computedSize); // Intrinsic size in cm
console.log('targetSize:', document.targetSize); // Target size in meters
console.log('rootElement.size.value:', document.rootElement?.size?.value);
console.log('document.scale:', document.scale); // Applied scaleUnderstanding the output:
computedSize: UIKit's rendered size in centimeters (based on your CSS)targetSize: The requested size in meters (from PanelUI maxWidth/maxHeight or ScreenSpace constraints)document.scale: Uniform scale factor applied to fit target while preserving aspect ratio
Example output:
computedSize: { width: 100, height: 50 } // 100cm × 50cm
targetSize: { width: 0.274, height: 0.168 } // 0.274m × 0.168m
document.scale: { x: 0.274, y: 0.274, z: 0.274 } // Scaled down by 0.274xScreenSpace Component Reference
The ScreenSpace component positions panels using CSS-like properties:
.addComponent(ScreenSpace, {
width: '90vw', // CSS size: px, vw, vh, %, auto
height: '90vh', // CSS size: px, vw, vh, %, auto
top: '5vh', // CSS position: px, %, vh, auto
bottom: 'auto', // CSS position: px, %, vh, auto
left: '5vw', // CSS position: px, %, vw, auto
right: 'auto', // CSS position: px, %, vw, auto
zOffset: 0.2, // Distance in meters from camera (default: 0.2m)
});How it works:
- In desktop mode: Panel attaches to camera at
zOffsetdistance, using CSS layout - In VR mode: Panel detaches from camera, returns to world space position
- Automatic switching handled by
ScreenSpaceUISystem
Common Workflow Tips
Centering Content
Use flexbox in your UIKitML for centered layouts:
.container {
display: flex;
flex-direction: column; /* Stack vertically */
justify-content: center; /* Center vertically */
align-items: center; /* Center horizontally */
}Sharp Borders
Set border-radius: 0 for square edges that align with grid systems:
.panel {
border-radius: 0; /* Square edges */
border-width: 0.15;
border-color: #27272a;
}UIKit Units
Remember: UIKit uses centimeters for sizing, world space uses meters:
width: 100in UIKitML = 100cm = 1.0mmaxWidth: 1.0in PanelUI = 1.0 meter
Cleanup Before Production
Before committing or going to production:
- Remove ScreenSpace component from your entity
- Remove or reposition backdrop if not needed for gameplay
- Restore camera position to gameplay view
- Remove debug logging of size signals
The panel will remain at its world space position defined by the entity's transform.
Example: Complete Development Setup
// 1. Enable spatialUI feature
World.create(container, {
features: { spatialUI: true },
}).then((world) => {
const { scene, camera } = world;
// 2. Create backdrop for UI development
const backdrop = new Mesh(
new BoxGeometry(20, 20, 0.1),
new MeshBasicMaterial({ color: 0x1a1a2e }),
);
backdrop.position.set(0, 0, -50);
scene.add(backdrop);
// 3. Position camera close to backdrop
camera.position.set(0, 0, -49.5);
camera.lookAt(0, 0, -50);
// 4. Create your UI panel with ScreenSpace
const panelHolder = new Group();
panelHolder.position.set(0, 1.5, -1.0); // World space position for VR
scene.add(panelHolder);
world
.createTransformEntity(panelHolder)
.addComponent(PanelUI, {
config: '/ui/my-panel.json',
maxWidth: 1.0,
maxHeight: 0.5,
})
.addComponent(ScreenSpace, {
// TEMPORARY for development
width: '90vw',
height: '90vh',
top: '5vh',
left: '5vw',
});
});Troubleshooting
Panel not filling screen:
- Check ScreenSpace width/height values
- Verify UIKitML doesn't have fixed small dimensions
Background still visible:
- Camera too far from backdrop - move closer (within 0.5m)
- Backdrop too small - increase size to 20×20 or larger
Panel doesn't return to world space in VR:
- Verify
spatialUI: truein World.create features - Check that ScreenSpaceUISystem is running
Size signals showing unexpected values:
- UIKit uses cm, world space uses meters (100cm = 1m)
- Check if aspect ratio constraints are being applied