iwsdk-ui-panel
skill✓Develop and iterate on IWSDK UI panels efficiently. Use when working on PanelUI components, debugging UI layout, or improving UI design in IWSDK applications.
apm::install
apm install @facebook/iwsdk-ui-panelapm::allowed-tools
Read, Edit, Write, Bash(npm *)
apm::skill.md
---
name: iwsdk-ui-panel
description: Develop and iterate on IWSDK UI panels efficiently. Use when working on PanelUI components, debugging UI layout, or improving UI design in IWSDK applications.
allowed-tools: Read, Edit, Write, Bash(npm *)
---
# 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:
```typescript
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:
```typescript
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:
```typescript
// 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:
1. Make changes to your `.uikitml` file
2. Take a screenshot to see the result against a clean backdrop
3. 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:
```typescript
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 scale
```
**Understanding 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.274x
```
## ScreenSpace Component Reference
The ScreenSpace component positions panels using CSS-like properties:
```typescript
.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 `zOffset` distance, 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:
```css
.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:
```css
.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: 100` in UIKitML = 100cm = 1.0m
- `maxWidth: 1.0` in PanelUI = 1.0 meter
## Cleanup Before Production
Before committing or going to production:
1. **Remove ScreenSpace component** from your entity
2. **Remove or reposition backdrop** if not needed for gameplay
3. **Restore camera position** to gameplay view
4. **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
```typescript
// 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: true` in 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