Develop

HUD Placement

Updated: Sep 4, 2026
The term HUD covers several placement behaviors. In immersive XR, place normal UI in the world or attach it to the object it controls. Use viewer-following UI only when information must remain discoverable, and avoid rigid head attachment for normal panels.

Choose the behavior

PriorityUseIWSDK mechanism
Recommended XR default
Panels and controls that belong to a place or object
Authored world transform or object parent
Optional leashed XR UI
Compact global UI that must remain discoverable
Follower targeting world.player.head
Browser-only overlay
Menus or status UI outside immersive XR
ScreenSpace
Exceptional head-locked UI
Tiny transient indicators that require exact view alignment
Parent to world.playerHeadEntity
ScreenSpace is not an in-XR head-locked HUD. Outside XR, it temporarily parents the UIKit document to the camera and applies CSS-like placement. When XR starts, the document returns to its authored world transform.

World-space UI

Place normal panels in the scene or parent contextual controls to the object they affect. World-space UI gives the interface a stable spatial reference and lets the viewer look away.
const panel = await world.assets.instantiate<UIKitMLAsset>('settings-panel');
const entity = world.createTransformEntity(panel);

entity.object3D!.position.set(0, 1.4, -1.5);
entity.object3D!.scale.setScalar(0.25);
Check readability, reach, and viewing angle on the target headset.

Browser viewport overlay

import { ScreenSpace } from '@iwsdk/core';

entity.addComponent(ScreenSpace, {
  width: '360px',
  height: '160px',
  top: '24px',
  right: '24px',
  zOffset: 0.2,
});
Author a useful world transform as well, because it becomes active when the session enters XR.

Leashed in-XR UI

import { FollowBehavior, Follower, UIKitMLAsset } from '@iwsdk/core';

const panel = await world.assets.instantiate<UIKitMLAsset>('hud-panel');
const entity = world.createTransformEntity(panel, { persistent: true });

entity.addComponent(Follower, {
  target: world.player.head,
  offsetPosition: [0, 0, -1],
  behavior: FollowBehavior.PivotY,
  speed: 1,
  tolerance: 0.4,
  maxAngle: 30,
});
FollowBehavior has three values:
  • FaceTarget turns the follower toward its target.
  • PivotY follows horizontal turns without applying head pitch or roll to the placement target.
  • NoRotation changes position without rotating the follower.
Tolerance and angle thresholds create a dead zone. Speed smooths movement toward a new target instead of copying every head pose.
For corner-like placement, adjust X and Z in offsetPosition. PivotY fixes the target height to the follower’s current Y position, so a Y offset is not applied. Judge readability by angular size and test the result on a headset.

Direct head attachment

const marker = await world.assets.instantiate<UIKitMLAsset>('aim-marker');
const markerEntity = world.createTransformEntity(marker, {
  parent: world.playerHeadEntity,
});

markerEntity.object3D!.position.set(0, 0, -1);
A direct child inherits every viewer pose. This motion can obstruct the scene and prevent the viewer from looking away.
Reserve direct head attachment for a small, transient, non-interactive marker whose purpose requires exact view alignment. Do not use it for menus, reading surfaces, or persistent status panels. If a reticle represents a world-space target, place it at the hit point or focus depth.