Develop and iterate on IWSDK UI panels efficiently. Use when working on PanelUI components, debugging UI layout, or improving UI design in IWSDK applications.
68
—
Does it follow best practices?
Impact
—
No eval scenarios have been run
Passed
No known issues
This skill teaches the efficient workflow for developing UI panels in IWSDK applications using temporary ScreenSpace positioning and backdrop techniques.
When working on a UI panel, follow these steps for rapid iteration:
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.
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);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.
Now you can rapidly iterate on your UI:
.uikitml fileThe ScreenSpace component makes the panel "follow" the camera, so it appears as a 2D overlay on your backdrop.
When you enter VR mode:
This dual-mode behavior is handled automatically by the ScreenSpaceUISystem.
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 ratioExample 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.274xThe 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:
zOffset distance, using CSS layoutScreenSpaceUISystemUse 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 */
}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;
}Remember: UIKit uses centimeters for sizing, world space uses meters:
width: 100 in UIKitML = 100cm = 1.0mmaxWidth: 1.0 in PanelUI = 1.0 meterBefore committing or going to production:
The panel will remain at its world space position defined by the entity's transform.
// 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',
});
});Panel not filling screen:
Background still visible:
Panel doesn't return to world space in VR:
spatialUI: true in World.create featuresSize signals showing unexpected values:
42af866
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.