Skip to content

InterfaceHost

InterfaceHost mounts an authored .rsx interface on a scene GameObject. Use it for a normal screen HUD, a purchase pad painted onto the floor, a sign in the 3D world, or a name and status display that follows a moving character.

One InterfaceHost mounts one complete RSX tree. That tree can contain many elements—text, images, progress bars, buttons, and nested components. Use multiple InterfaceHost GameObjects when parts of the interface need independent transforms, visibility, or lifecycles.

Quick Setup

  1. Create or select a GameObject in the scene.
  2. Add the InterfaceHost component in the Inspector.
  3. Set Source to the .rsx interface file.
  4. Choose Screen or World in Space.
  5. If you choose World, the Inspector adds Transform3D when the GameObject does not already have one.
  6. Position the interface with the normal Transform3D position, rotation, and scale fields. World interfaces use X, Y, and Z like every other 3D GameObject.

Every InterfaceHost RSX source must import a paired .rstyle file. This small purchase-pad pair is a complete starting point:

rsx
// PurchasePad.rsx
import styles from "./PurchasePad.rstyle"

class PurchasePadView extends UIComponent {
  render {
    <View automationId="purchasePad" accessibilityLabel="Purchase funding" style={styles.pad}>
      <View automationId="purchasePadProgress" style={styles.progress} />
      <View style={styles.costRow}>
        <View accessibilityLabel="Money" style={styles.moneyBill} />
        <Text automationId="purchasePadPrice" accessibilityLabel="Remaining purchase price" style={styles.price}>100</Text>
      </View>
    </View>
  }
}
rstyle
// PurchasePad.rstyle
extends StyleSet

export default StyleSet.create({
  pad: {
    width: 360,
    height: 200,
    alignItems: "center",
    justifyContent: "center",
    overflow: "hidden",
    backgroundColor: "#1639238A",
    borderRadius: 28
  },
  progress: {
    position: "absolute",
    left: 0,
    top: 0,
    width: 0,
    height: "100%",
    backgroundColor: "#22C55EB8"
  },
  costRow: { flexDirection: "row", alignItems: "center", gap: 18 },
  moneyBill: { width: 76, height: 48, backgroundColor: "#22B65EFF", borderRadius: 9 },
  price: { color: "#FEF3C7FF", fontSize: 60, fontWeight: "900" }
})

Save both files together, then choose PurchasePad.rsx in Source. A missing or invalid style import prevents the surface from mounting and reports onLoadFailed.

Keep the pad focused on the transaction: one money symbol, the remaining cost, and the funding fill. Put instructions such as “Open the restaurant” in a separate transient Screen InterfaceHost so the objective can animate or disappear without changing the world pad.

There is no second InterfaceHost transform. This keeps parenting predictable: a child InterfaceHost follows the full position, rotation, and scale chain of its parent GameObjects.

In UI Builder, enable Scene (uiBuilder.viewport.showScene) to preview the active scene behind the RSX surface and judge its real world placement.

Screen And World Space

BehaviorScreenWorld
PlacementScreen overlayGameObject Transform3D
Parent transformNot used for screen placementFull parent chain
Scene depthAlways above the 3D sceneControlled by Depth Test
Scene shadowsNeverOptional Receive Shadows
UISurface pointer inputSupportedCamera-ray projection with bounds, face, distance, and depth checks

screen is the default. Screen hosts use normal UISurface input and ignore world-only rendering settings.

world renders the complete RSX surface as one transparent rectangle in the 3D scene. The rectangle can lie on a floor or wall, stand as a sign, or move as a child of another GameObject.

Activation And Visibility

enabled controls the InterfaceHost lifecycle. Disabling the host GameObject—or any ancestor—makes the host inactive. ReGame removes it from rendering, UI lookup, and accessibility publication immediately, then emits onUnmounted while releasing the retained surface on the next frame. Enabling the hierarchy again creates a fresh mount and emits the normal mount and readiness events again.

hidden is a visual choice, not a lifecycle choice. A hidden host skips rendering but remains mounted, continues processing, and keeps its retained element handles. Use hidden for short visual pauses. Use enabled = false when an inactive purchase zone, HUD, or world panel should stop participating in UI systems entirely.

Inside an onUnmounted callback, the outgoing surface is still queryable so cleanup code can inspect it or release retained handles. Treat those handles as invalid as soon as the callback returns.

Properties

Inspector labelPropertyDefaultUsed by
SourcesourceRef (editor)EmptyScreen and World
SpacemountSpacescreenScreen and World
Surface SizesurfaceSize512 x 256World
Pixels Per UnitpixelsPerUnit100World
Depth TestdepthTestOnWorld
Receive ShadowsreceiveShadowsOffWorld
Double SideddoubleSidedOnWorld
Depth BiasdepthBias0.0005World

World Size

surfaceSize is the RSX layout and render-target size in pixels. pixelsPerUnit converts that size into 3D units:

text
world width  = surfaceSize.x / pixelsPerUnit
world height = surfaceSize.y / pixelsPerUnit

At the defaults, a 512 x 256 surface at 100 pixels per unit occupies 5.12 x 2.56 world units before Transform3D scale is applied.

Increase surfaceSize when the RSX layout needs more logical room or texture detail. Change pixelsPerUnit when the same pixel layout should occupy a different physical size. Very large render targets cost more GPU memory and rendering work.

Each surfaceSize axis and pixelsPerUnit is clamped to the supported 1…4096 range.

Depth Test

Depth Test is on by default. When enabled, ordinary 3D geometry can appear in front of the world interface. Turn it off only when the interface must remain visible through scene objects.

World InterfaceHosts test the existing scene depth but do not write their transparent rectangle into the depth buffer. This avoids one translucent interface incorrectly hiding another one drawn later.

Receive Shadows

Enable Receive Shadows when shadows from scene geometry should darken the visible InterfaceHost artwork. This is the option that makes a character, worker, or prop shadow appear across a money icon or purchase pad instead of continuing underneath it unchanged.

Shadow receiving is opt-in and only affects World hosts. It requires an active shadow-producing DirectionalLight3D and scene geometry whose renderer has shadow casting enabled. The InterfaceHost remains otherwise unlit, so its authored colors stay unchanged outside the shadow.

Receive Shadows does not mean Cast Shadows. The checkbox lets other objects' shadows fall onto the interface. The transparent InterfaceHost rectangle does not cast its own shadow onto the floor. Screen hosts never participate in scene shadows.

Double Sided

When Double Sided is on, both faces of the world rectangle render. Turn it off for a floor decal, wall panel, or sign that should only be visible from its front. If a one-sided interface disappears, rotate its Transform3D so its front faces the camera or temporarily enable Double Sided while positioning it.

Depth Bias

depthBias moves only the depth comparison slightly toward the camera. Use it to stop flicker when a world InterfaceHost is almost coplanar with a floor or wall.

First place the interface a tiny physical distance above the surface with Transform3D. Then use the smallest depth bias that removes the remaining z-fighting. Depth Bias is not a replacement for normal X, Y, and Z placement.

depthBias is clamped to 0…0.05.

Floor Purchase Pad

A floor purchase pad normally combines visual UI and gameplay collision:

  1. Create a GameObject for the purchase zone.
  2. Add Transform3D, InterfaceHost, Area3D, and the purchase-zone RGScript component.
  3. Set InterfaceHost Space to World and choose the pad .rsx source.
  4. Rotate Transform3D around X by about -90 degrees so the front of the RSX surface faces upward.
  5. Move it a small distance above the floor.
  6. Keep Depth Test on.
  7. Turn Receive Shadows on so workers, players, and props can shadow the money artwork.
  8. Usually turn Double Sided off and keep a small Depth Bias only if needed.
  9. Size and position the Area3D shape over the same purchase zone.
  10. Give the player GameObject the player tag when using the filtered collision example below.

For hold-to-fund purchases, update the remaining price and grow a clipped fill from left to right while the player stays inside the area. Keep partial funding in the authoritative gameplay state when the player leaves; the InterfaceHost only presents that state.

World UISurface controls receive the same mouse, touch, and pen events as Screen hosts after the active 3D camera ray is projected into the surface's pixel coordinates. Use Area3D when the interaction is based on player occupancy rather than a pointer:

rgscript
class PurchasePadController extends Component {
  let area: Area3D

  function _ready() {
    area = getComponent<Area3D>()
    area.onCollide("player", (other: GameObject) => {
      // Check the player's money and unlock the zone here.
      let price: Text = UI.text("purchasePadPrice")
      if (price != null) {
        price.text = "OPEN"
      }
    })
  }
}

An Area3D participates only while its full GameObject hierarchy is enabled and unpaused. hidden and visible control presentation only; they do not disable overlap detection. To deactivate a sensor, disable the area GameObject or an ancestor. Disabling ends current overlaps once through onCollideEnd; enabling the hierarchy again allows a new onCollide when an eligible body overlaps. On a new overlap, onCollide runs before that frame's first onCollideUpdate. This makes it safe to keep purchase and service triggers under an initially disabled buildable-station interaction branch while their visible pads live in a separately animated presentation branch.

The onCollide subscription uses ReGame's normal owner-bound event cleanup.

Moving Overhead Interface

To make a name, health bar, order icon, or speech label follow a moving character:

  1. Create a child GameObject under the character.
  2. Add Transform3D and InterfaceHost to the child.
  3. Set Space to World.
  4. Use the child's local Transform3D position to offset the interface above the character.
  5. Keep Depth Test on so walls and nearby objects can occlude it naturally.
  6. Leave Receive Shadows off when maximum label readability is more important, or enable it when the label should feel physically present in the scene.

The child follows the parent's full transform automatically. Moving a parent does not rerender unchanged RSX content; only the world rectangle's transform changes.

World InterfaceHosts do not automatically face the camera. Rotate the child from gameplay code if a billboard-style overhead display is required.

Events

InterfaceHost exposes lifecycle and presentation changes through the shared GameObject event lane:

EventMeaning
onMountedThe retained UISurface is built, laid out, registered, and ready to query.
onUnmountedThe active surface is about to be released. The outgoing surface remains queryable during this callback only.
onMountSpaceChangedmountSpace changed between Screen and World.
onLayoutThe retained RSX tree completed layout.
onGeometryChangedA successful mount/rebuild completed, or surfaceSize/pixelsPerUnit changed world geometry.
onRenderSettingsChangedDepth Test, Receive Shadows, Double Sided, or Depth Bias changed.
onRenderTargetReadyThe current World surface texture is ready.
onRenderTargetInvalidatedThe current World surface texture is no longer authoritative.
onLoadFailedSource loading, RSX building, or render-target creation failed.

State changes before the matching event fires, so a callback can immediately read the new value:

rgscript
class PadPresentation extends Component {
  let host: InterfaceHost

  function _ready() {
    host = getComponent<InterfaceHost>()
    host.onRenderSettingsChanged(() => {
      console.log("Receive Shadows: " + host.receiveShadows)
    })
  }
}

Subscriptions return an EventController. Keep the controller when you need to pause or cancel a long-lived subscription. GameObject event subscriptions survive a surface rebuild or unmount; they end when explicitly cancelled, when the subscribing script is cleaned up, or when the event target is destroyed.

During initial scene loading, ReGame builds active InterfaceHost surfaces before script _ready() so the mounted UI is available when _ready() begins. An initially disabled host does not mount until its hierarchy becomes enabled. Query an active mounted surface directly from _ready(). Subscribe there for later rebuild, layout, geometry, unmount, and failure events; the initial onMounted, onLayout, onGeometryChanged, and onLoadFailed notifications may already have occurred.

Platform And Input Notes

  • Desktop and Android World hosts use the shared 3D OpenGL/GLES renderer, including depth testing and optional directional-shadow receiving.
  • Native iOS currently supports Screen hosts through its 2D Metal renderer. World hosts require the future native 3D Metal camera/depth/shadow path and are not rendered there yet. For a cross-platform floor pad today, compose a lightweight MeshSource/MeshRenderer fallback and switch between it and the World host from onRenderTargetReady / onRenderTargetInvalidated; keep exactly one presentation visible at a time.
  • Screen hosts support the shared mouse, touch, and pen input path.
  • World hosts use the active perspective or orthographic Camera3D for ray-projected UISurface input. Pointer capture continues on the same host until Up or Cancel.
  • Input priority is Screen UISurface, then nearest eligible World UISurface, then 3D physics picking. See Pointer Input And Joystick.
  • World hosts are transparent 3D rectangles. They can receive supported scene shadows but do not cast an InterfaceHost-shaped shadow.

Troubleshooting

ProblemCheck
World interface is invisibleConfirm Source is valid, rotate its front toward the camera, or enable Double Sided while positioning.
Interface is behind an objectThis is expected with Depth Test on; move it or turn Depth Test off only if it must show through geometry.
Interface flickers against a floor or wallMove it slightly off the surface, then add a small Depth Bias.
Interface is the wrong physical sizeCheck both Surface Size and Pixels Per Unit, then Transform3D scale.
Shadow still passes underneath the artworkConfirm Space is World, Receive Shadows is on, a DirectionalLight3D is active, and the covering mesh casts shadows.
Overhead interface does not followMake the InterfaceHost GameObject a child of the moving object and use a local Transform3D offset.
World button does not clickUse Area3D or a 3D raycast for interaction; direct World UISurface pointer projection is not implemented yet.

ReGame engine documentation