API / UI

Retained GUI controls

Build reusable, parented 2D GUI controls with profiles, events, and helpers.

Retained GUI controls

game.gui is BornEngine’s retained, object-oriented 2D GUI. Create controls as objects, attach them to a parent, and keep their state between frames. The engine lays out and submits the tree after Game.render(); native responses are applied before the next Game.loop().

Choose game.gui or game.ui

Use game.ui when a small immediate-mode HUD is easiest to describe again during each render() call. Use game.gui when you want reusable controls, parent-child organization, subclass hooks, profiles, or persistent widget state. Both APIs render through the same egui context and surface. Their IDs and response stores stay separate, and the developer inspector remains on top when enabled.

Platform status

watchOS: GUI controls do not work on watchOS in the current release: controls do not render and GUI input/events are unavailable. This limitation is temporary. A future SwiftUI adapter is planned, with no delivery date promised. Check game.gui.isAvailable() before building platform-specific behavior.

Import and attach controls

Import from the package root or from the gui subpath:

typescript
import { GUI, GuiButton, GuiPanel, GuiScroll, GuiText, Vector2D } from '@bornengine/engine';
// Or: import { GUI, GuiButton, GuiPanel, GuiScroll, GuiText } from '@bornengine/engine/gui';

Construct controls independently, then attach one or more roots to the Game-owned manager. A child can only belong to one parent at a time.

typescript
const panel = new GuiPanel({ position: new Vector2D(24, 24), width: 320, height: 180 });
const title = new GuiText({ position: new Vector2D(12, 10), width: 280, height: 28 });
title.setText('Inventory');
panel.addControl(title);
game.gui.addControl(panel);

Geometry and parent helpers

x and y are logical-pixel offsets from the parent content origin, after the parent profile’s padding. A GuiWindow also reserves its title bar above the child content. A root control uses the game viewport as its parent bounds. center() centers on both axes of the current parent content area; centerHorizontal() and centerVertical() anchor one axis. Anchors update after parent or viewport resize. Geometry setters return the control for chaining.

typescript
const scroll = new GuiScroll({ position: Vector2D.zero(), width: 420, height: 300 });
scroll.center();
scroll.moveBy(Vector2D.right().scale(24)).centerVertical();
scroll.setSize(460, 320);

const child = new GUI({ position: new Vector2D(12, 16), width: 120, height: 32 });
scroll.addControl(child);
const parent = child.getParent();
const screenPoint = child.localToGlobal(Vector2D.zero());
const localPoint = child.globalToLocal(screenPoint);
const position = child.getPosition();
child.setPosition(position.add(new Vector2D(4, 0)));

Positions accept Vector2D or any { x, y } value through position and setPosition(). getPosition(), localToGlobal(), and globalToLocal() return independent Vector2D snapshots. moveBy(offset) translates the control and clears both center anchors. Existing x/y, setX()/setY(), and setPosition(x, y) calls remain supported; explicit x or y options override only the matching component of position. Width and height remain separate dimensions.

Common geometry and tree methods:

MethodsPurpose
getX() / setX(x), getY() / setY(y)Read or set a parent-relative offset; setting one axis clears only that axis’s center anchor.
position?: Vector2DLike, getPosition() / setPosition(position) / moveBy(offset)Set and read parent-relative position with Vector2D; numeric x/y and setPosition(x, y) are kept for convenience and compatibility. Returned positions are detached snapshots.
getSize() / setSize(width, height), resize(x, y, width, height)Read or update dimensions. Width and height must be finite and non-negative.
center(), centerHorizontal(), centerVertical()Anchor the control to its parent’s center.
getParent(), getRoot(), getControls(), addControl(control), removeControl(control), clearControls()Inspect and manage the retained tree. parent is a read-only getter.
localToGlobal(point), globalToLocal(point)Accept vector-like positions and return Vector2D coordinates through the current ancestor chain.
show(), hide(), setVisible(value), setActive(value)Control visibility and whether a subtree participates in GUI input/rendering.
setClipChildren(value), setClipToBounds(value)Clip descendants or the control’s own drawing to bounds. GuiScroll clips children to its viewport.
getProfile() / setProfile(profile), setOwnProfile(profile?)Read, share, or clone a visual profile.
bringToFront(), pushToBack()Change sibling/root draw order.
destroy()Detach the control and its descendants permanently.

GUIManager also exposes getControls(), isAvailable(), wantsPointerInput(), and wantsKeyboardInput(). Check input-capture methods when deciding whether gameplay should react to the same pointer or keyboard input; the GUI does not automatically consume game input.

Profiles

GuiProfile holds normal, hover, disabled, text, and selection colors; font and alignment; spacing, border, opacity, background texture, shadow, focus and modality settings, cursor, and optional button sounds. Profiles are shared by reference until cloned. setOwnProfile() gives one control an independent copy.

typescript
import { GUIProfiles } from '@bornengine/engine/gui';

const button = new GuiButton({ width: 160, height: 36 });
const profile = button.setOwnProfile(GUIProfiles.get('button'));
profile.normalColor = { r: 0.08, g: 0.24, b: 0.5, a: 1 };
button.setText('Continue');

Built-in names include default, text, button, window, scroll, checkbox, radio, popup, slider, progress, tree, list, and blue. Use GUIProfiles.register(name, profile) for an application-wide profile; duplicate names and unknown lookups throw. Use GUIProfiles.clone(name) or control.setOwnProfile() before changing a profile for one control.

Built-in controls

Every concrete control extends GUI; add it to a parent with addControl() or to the root with game.gui.addControl(). Controls accept optional GUIControlOptions for geometry, visibility, clipping, and activity.

Base and layout

ClassMethods and purpose
GUIExtensible base/container. Geometry, tree, visibility, focus, cursor, hints, minimum size, z-order, and lifecycle helpers are available on every control.
GuiPanelBasic rectangular container. Add children and choose whether they clip to its bounds.
GuiWindowTitled, movable, resizable panel. getTitle() / setTitle(title) manage its title; setMovable(enabled) and setResizable(enabled) enable native dragging and resizing. setClosable(enabled) adds a close button that hides the window; call show() to reopen it.
GuiScrollScrollable container with child clipping. Set horizontal/vertical scrollbar modes to 'alwaysOn', 'alwaysOff', or 'dynamic'; configure setScrollBarThickness(pixels).
GuiBitmapBorderDraws the profile background bitmap on its four edges and keeps the interior on normalColor. profile.border.width sets edge thickness; setTiled(true) repeats the bitmap along each edge at its native length, while the edge thickness is fitted to the control. With tiling off, each edge stretches the bitmap.
GuiStretchStretches its children from the virtual area set by setClientSize(width, height) to the control’s physical size. Child geometry and pointer-local coordinates use the same scale.
GuiFrameSetLays out direct children in row-major cells. setColumnCount(n), setRowCount(n), and setSplitterWidth(pixels) configure the grid; drag a splitter to resize adjacent cells.

Buttons and values

ClassMethods and purpose
GuiButtonBaseAbstract button base with getText() / setText(text).
GuiButtonClickable text button. Override onAction(event) for an action.
GuiCheckBoxBoolean choice. Use getValue() / setValue(value); changes call onChange(event).
GuiRadioButtonBoolean choice with optional sibling exclusivity through setGroup(groupId).
GuiBitmapButtonButton with setTextures({ normal, hover, pressed, disabled }) and getTextures(). Textures must be loaded by the same Game.
GuiSliderNumeric value input. Set its range with setRange(minimum, maximum) and access getValue() / setValue(value).

Text and editing

ClassMethods and purpose
GuiTextSingle or wrapped text with getText() / setText(text).
GuiMLTextMulti-line text control.
GuiTextEditEditable single-line text. selectAll(), clear(), setMaxLength(n), setPassword(enabled), setNumbersOnly(enabled), and getSelection() configure the editor.
GuiMLTextEditMulti-line editable text with the same length, password, numeric-only, and selection methods.
GuiTextEditSliderText edit paired with a numeric value. Use setRange(minimum, maximum) and getValue() / setValue(value) alongside text-edit options.

Selection and navigation

ClassMethods and purpose
GuiArrayAbstract base for controls backed by a typed item list. getItems() and getItemCount() inspect the list.
GuiPopUpMenuadd(label, id), clear(), setSelected(id), getSelected(), and getSelectedText() manage choices.
GuiPopUpEditEditable text field with an item popup; adds getText() / setText(text). Native text edits return to TypeScript before the next Game.loop.
GuiTreeViewaddNode(label, value?), addNodeByPath(path, value?), clearNodes(), getSelected(), and getSelectedPath() build and inspect a bounded tree.
GuiTextListaddRow(id, text), removeRow(id), clearRows(), and getSelected() manage rows.
GuiTabHorizontal tab bar with pages below it. addTab(label, id), setSelected(id), and getSelected() choose a page.
GuiMenuHorizontal menu bar that invokes the selected item’s callback and bubbles an action event.
GuiContextMenuContext menu that opens at the pointer on a secondary click inside its parent, invokes the selected item’s callback, bubbles an action event, and closes after activation. openAt(position, button) accepts a vector-like position; the numeric openAt(x, y, button) form remains supported.

Images, progress, and custom drawing

ClassMethods and purpose
GuiBitmapDisplays a Game-owned texture. setTexture(texture), setTint(color), setOpacity(value), setRotation(degrees), and setZoom(value) configure it.
GuiShowImgImage-display control with the same texture, tint, opacity, rotation, and zoom methods.
GuiProgressUnit-interval progress value; setValue(value) clamps to [0, 1].
GuiDrawingPanelOrdered, panel-clipped drawLine, drawRect, drawCircle, drawText, drawImage, drawPolyline, drawPolygon, and clearDrawing commands.

Textures are accepted only when they are loaded and owned by the current Game. Foreign or unloaded images are omitted. Background and control textures are registered through the same egui texture path as game.ui.image().

Events, focus, and response timing

Override only the hooks a control needs: onAction, onChange, onFocus, onBlur, onPointerEnter, onPointerLeave, onPointerMove, onPointerDown, onPointerUp, onPointerDrag, onWheel, onKeyDown, and onKeyUp. Lifecycle hooks include onAdd, onRemove, onShow, onHide, onWake, onSleep, onMove, and onResize.

typescript
class ApplyButton extends GuiButton {
  protected override onAction(event: GUIEvent): void {
    console.log(event.target === this, event.currentTarget === this);
  }
}

GUI events carry target, currentTarget, localPosition and globalPosition as Vector2D snapshots, plus the compatible scalar localX/localY and globalX/globalY fields, key/button/wheel data, and modifiers when present. They bubble from the target to its parents; call event.stopPropagation() to stop bubbling. Use focus(), blur(), isFocused(), makeFirstResponder(), and isFirstResponder() for keyboard focus. Hidden, inactive, detached, or destroyed controls do not receive stale input responses.

The native backend evaluates both UI APIs after game rendering. game.gui applies the completed response snapshot during the next frame’s service update, before Game.loop(). Value setters made in TypeScript take precedence over an older pending native value. Use game.gui.isAvailable() before relying on GUI rendering or input; unavailable targets return false and dispatch no GUI events.