HytaleJS
GuidesCustom UI

UIBuilder

Programmatically generate .ui files with TypeScript

The UIBuilder provides a fluent TypeScript API for generating Hytale UI DSL files programmatically. Instead of writing raw DSL strings, you can use type-safe builder methods with full IDE autocompletion.

Quick Start

import { UIBuilder, group, label, slot } from "@hytalejs.com/core";

const ui = new UIBuilder()
  .import("C", "../Common.ui")
  .root(
    group({ id: "MyPanel" })
      .anchor({ width: 300, height: 200 })
      .background({ color: "#1a2530", opacity: 0.9 })
      .padding({ full: 16 })
      .children(
        label({ id: "Title", text: "Hello World" })
          .style({ fontSize: 24, textColor: "#FFFFFF", renderBold: true })
      )
  )
  .build();

This generates:

$C = "../Common.ui";

Group #MyPanel {
  Anchor: (Width: 300, Height: 200);
  Background: (Color: #1a2530(0.9));
  Padding: (Full: 16);
  Label #Title {
    Text: "Hello World";
    Style: (FontSize: 24, TextColor: #FFFFFF, RenderBold: true);
  }
}

UIBuilder Class

The main class for constructing UI documents.

Methods

MethodDescription
import(alias, path)Add an import statement
root(element)Set single root element
roots(...elements)Set multiple root elements
build()Generate the DSL string
const ui = new UIBuilder()
  .import("C", "../Common.ui")
  .import("Sounds", "../Sounds.ui")
  .roots(
    group().template("$C.@PageOverlay").children(...),
    group().template("$C.@BackButton")
  )
  .build();

Element Functions

Create UI elements using factory functions:

Basic Elements

FunctionDescription
group(props?)Container element
label(props?)Text display
textButton(props?)Button with text
button(props?)Icon button
textField(props?)Text input
sprite(props?)Image display
checkbox(props?)Boolean toggle
slider(props?)Numeric slider
progressBar(props?)Progress indicator

Special Elements

FunctionDescription
slot(id)Template slot reference (#id)
backButton()Back button element
timerLabel(props?)Timer display
dropdownBox(props?)Dropdown selector
itemSlot(props?)Inventory slot
itemGrid(props?)Inventory grid

Element Props

All element functions accept optional props:

interface ElementProps {
  id?: string;
  text?: string;
  placeholder?: string;
  texturePath?: string;
  value?: boolean | number;
  min?: number;
  max?: number;
}

Examples:

group({ id: "Container" })
label({ id: "Title", text: "Welcome" })
slider({ id: "Volume", min: 0, max: 100, value: 50 })
checkbox({ id: "Enabled", value: true })
textField({ id: "Name", placeholder: "Enter name..." })

Element Methods

All elements support these chainable methods:

Layout & Positioning

element
  .anchor({ width: 200, height: 100, top: 10, right: 20 })
  .layoutMode("Top")
  .padding({ full: 16 })
  .flexWeight(1)
  .visible(true)

Anchor Props

PropertyDescription
width, heightFixed dimensions
top, bottom, left, rightPosition offsets
fullShorthand for all sides
horizontal, verticalShorthand for left/right and top/bottom
minWidth, maxWidthSize constraints

Layout Modes

ModeDescription
"Top"Stack children from top
"Left"Stack children from left
"Center"Center children horizontally
"Middle"Center children vertically
"CenterMiddle"Center both axes
"Full"Children fill container

Styling

element
  .background({ color: "#1a2530", opacity: 0.85 })
  .style({
    fontSize: 16,
    textColor: "#FFFFFF",
    renderBold: true,
    horizontalAlignment: "Center"
  })

Background Props

PropertyDescription
colorHex color (e.g., "#1a2530")
opacity0-1 transparency
texturePathImage path
border9-patch border size

Style Props

PropertyDescription
fontSizeFont size in pixels
textColorText color
renderBoldBold text
renderUppercaseUppercase transform
horizontalAlignment"Start", "Center", "End"
verticalAlignment"Top", "Center", "Bottom"
wrapText wrapping

Content

label({ id: "Title" })
  .text("Hello World")

textField({ id: "Input" })
  .raw("PlaceholderText", '"Enter text..."')

Templates

group()
  .template("$C.@PageOverlay")
  .param("Text", '"My Title"')
  .param("Sounds", "$Sounds.@ButtonsCancel")

Children

group({ id: "Container" })
  .children(
    label({ text: "First" }),
    label({ text: "Second" }),
    group({ id: "Nested" }).children(...)
  )

Template Slots

When using templates like @DecoratedContainer, use slot() for slot references:

group()
  .template("$C.@DecoratedContainer")
  .anchor({ width: 400 })
  .children(
    slot("Title").children(
      group().template("$C.@Title").param("Text", '"My Page"')
    ),
    slot("Content")
      .padding({ vertical: 32, horizontal: 45 })
      .children(
        label({ id: "message", text: "Content here" })
      )
  )

This generates:

$C.@DecoratedContainer {
  Anchor: (Width: 400);
  #Title {
    $C.@Title {
      @Text = "My Page";
    }
  }
  #Content {
    Padding: (Vertical: 32, Horizontal: 45);
    Label #message {
      Text: "Content here";
    }
  }
}

Note: Use slot("Title") instead of group({ id: "Title" }) for template slots. Using group would generate Group #Title instead of #Title, which breaks the template slot binding.

Complete Example: Custom Page

import { UIBuilder, group, label, slot } from "@hytalejs.com/core";

const EXAMPLE_PAGE = new UIBuilder()
  .import("C", "../Common.ui")
  .import("Sounds", "../Sounds.ui")
  .roots(
    group()
      .template("$C.@PageOverlay")
      .layoutMode("Middle")
      .children(
        group()
          .template("$C.@DecoratedContainer")
          .anchor({ width: 400 })
          .children(
            slot("Title").children(
              group().template("$C.@Title").param("Text", '"Example Page"')
            ),
            slot("Content")
              .padding({ vertical: 32, horizontal: 45 })
              .children(
                label({ id: "title" })
                  .style({ renderBold: true, textColor: "#FFFFFF" })
                  .text("Welcome!"),
                label({ id: "message" })
                  .anchor({ top: 20 })
                  .style({ textColor: "#94a7bb" })
                  .text("This is an example page."),
                group()
                  .layoutMode("Center")
                  .anchor({ top: 30 })
                  .children(
                    group({ id: "CloseButton" })
                      .template("$C.@TextButton")
                      .param("Sounds", "$Sounds.@ButtonsCancel")
                      .text("Close")
                      .flexWeight(1)
                  )
              )
          )
      ),
    group().template("$C.@BackButton")
  )
  .build();

const asset = new ByteArrayCommonAsset("UI/Custom/Pages/Example.ui", EXAMPLE_PAGE);
CommonAssetModule.get().addCommonAsset("myplugin", asset);

Complete Example: HUD Scoreboard

import { UIBuilder, group, label } from "@hytalejs.com/core";

const SCOREBOARD_HUD = new UIBuilder()
  .import("C", "../Common.ui")
  .root(
    group({ id: "Scoreboard" })
      .anchor({ right: 20, top: 100, width: 200, height: 170 })
      .layoutMode("Top")
      .background({ color: "#0a0e14", opacity: 0.85 })
      .padding({ full: 12 })
      .children(
        label({ id: "Title" })
          .style({
            fontSize: 24,
            textColor: "#f5c542",
            renderBold: true,
            renderUppercase: true,
            horizontalAlignment: "Center"
          })
          .anchor({ height: 30 })
          .text("My Server"),
        group({ id: "Separator" })
          .anchor({ height: 1, top: 8 })
          .background({ color: "#2b3542" }),
        group({ id: "PlayerRow" })
          .layoutMode("Left")
          .anchor({ height: 22, top: 10 })
          .children(
            label({ id: "PlayerLabel" })
              .style({ fontSize: 13, textColor: "#8a9aab", verticalAlignment: "Center" })
              .anchor({ width: 80 })
              .text("Player:"),
            label({ id: "PlayerValue" })
              .style({ fontSize: 13, textColor: "#ffffff", verticalAlignment: "Center", renderBold: true })
              .flexWeight(1)
              .text("Unknown")
          ),
        group({ id: "OnlineRow" })
          .layoutMode("Left")
          .anchor({ height: 22, top: 4 })
          .children(
            label({ id: "OnlineLabel" })
              .style({ fontSize: 13, textColor: "#8a9aab", verticalAlignment: "Center" })
              .anchor({ width: 80 })
              .text("Online:"),
            label({ id: "OnlineValue" })
              .style({ fontSize: 13, textColor: "#5cb85c", verticalAlignment: "Center", renderBold: true })
              .flexWeight(1)
              .text("0")
          )
      )
  )
  .build();

On this page