User Interface

Build interactive UI elements like buttons, text, and progress bars.

Global Theme

js
// Override any theme value globally — all elements inherit
game.ui.theme.set({
    primaryColor:    "#e63946",
    fontFamily:      "Press Start 2P, monospace",
    fontSize:        12,
    borderRadius:    4,
    backgroundColor: "#0a0a1a",
});

// Reset to built-in defaults
game.ui.theme.reset();

UIPanel — container / background box

js
import { UIPanel } from "kernelplay-js"; // Assuming UIPanel is exported from main library

const panel = game.ui.add(new UIPanel({
    anchor: "center",
    offset: { x: 0, y: 0 },
    width:  300,
    height: 200,
    zIndex: 0,

    // per-element style overrides
    style: {
        surfaceColor: "#1a1a2e",
        borderColor:  "#e63946",
        borderWidth:  2,
        borderRadius: 12,
    },
}));

// hide / show
panel.visible = false;
panel.visible = true;

UIText — label

js
import { UIText } from "kernelplay-js"; // Assuming UIText is exported from main library

const label = game.ui.add(new UIText({
    text:   "Score: 0",
    anchor: "topLeft",
    offset: { x: 20, y: 20 },
    style: {
        textColor:  "#ffffff",
        fontSize:   18,
        fontWeight: "bold",
    },
}));

// update text every frame
label.text = `Score: ${this.score}`;

UIButton — clickable button

js
import { UIButton } from "kernelplay-js"; // Assuming UIButton is exported from main library

const btn = game.ui.add(new UIButton({
    label:  "Play",
    anchor: "center",
    offset: { x: 0, y: 0 },
    width:  160,
    height: 48,
    zIndex: 1,
    style: {
        primaryColor: "#4a90e2",
        hoverColor:   "#5aa0f2",
        pressColor:   "#3a80d2",
        fontSize:     16,
        fontWeight:   "bold",
    },
}));

btn.onClick = () => {
    console.log("Play clicked!");
    game.sceneManager.startScene("Game");
};

// disable button
btn.disabled = true;

// re-enable
btn.disabled = false;

UIImage — sprite / icon

js
import { UIImage } from "kernelplay-js"; // Assuming UIImage is exported from main library

const icon = game.ui.add(new UIImage({
    src:    "./assets/health_icon.png",
    anchor: "topLeft",
    offset: { x: 10, y: 10 },
    width:  32,
    height: 32,
}));

UIProgressBar — health bar / loading bar

js
import { UIProgressBar } from "kernelplay-js"; // Assuming UIProgressBar is exported from main library

const healthBar = game.ui.add(new UIProgressBar({
    value:     1.0,          // 1.0 = full
    direction: "left",       // fills left → right
    anchor:    "topLeft",
    offset:    { x: 20, y: 20 },
    width:     200,
    height:    20,
    showText:  false,
    style: {
        progressTrackColor: "#333350",
        progressFillColor:  "#e74c3c",   // red health bar
        borderRadius:       10,
    },
}));

// update when player takes damage
healthBar.setValue(this.health / this.maxHealth);

// other directions
const chargeBar = game.ui.add(new UIProgressBar({
    value:     0,
    direction: "left",     // "left" | "right" | "up" | "down"
    anchor:    "bottomCenter",
    offset:    { x: 0, y: 20 },
    width:     120,
    height:    12,
    style: { progressFillColor: "#f39c12" },
}));
chargeBar.setValue(this.charge / this.maxCharge);

UICheckbox — toggle option

js
import { UICheckbox } from "kernelplay-js"; // Assuming UICheckbox is exported from main library

const sfxToggle = game.ui.add(new UICheckbox({
    label:   "Sound Effects",
    checked: true,
    anchor:  "center",
    offset:  { x: 0, y: -20 },
    width:   200,
    height:  30,
}));

sfxToggle.onChange = (checked) => {
    game.audio.setSFXVolume(checked ? 1 : 0);
};

UISlider — volume / sensitivity control

js
import { UISlider } from "kernelplay-js"; // Assuming UISlider is exported from main library

const volumeSlider = game.ui.add(new UISlider({
    value:     0.8,
    min:       0,
    max:       1,
    showValue: true,
    anchor:    "center",
    offset:    { x: 0, y: 40 },
    width:     220,
    height:    30,
}));

volumeSlider.onChange = (value) => {
    game.audio.setMasterVolume(value);
};

UIInputField — text input

js
import { UIInputField } from "kernelplay-js"; // Assuming UIInputField is exported from main library

const nameField = game.ui.add(new UIInputField({
    placeholder: "Enter your name...",
    value:       "",
    maxLength:   20,
    anchor:      "center",
    offset:      { x: 0, y: 0 },
    width:       260,
    height:      42,
}));

nameField.onChange  = (value) => console.log("Typing:", value);
nameField.onSubmit  = (value) => {
    console.log("Name submitted:", value);
    savePlayerName(value);
};

// password field
const passField = game.ui.add(new UIInputField({
    placeholder: "Password",
    password:    true,
    anchor:      "center",
    offset:      { x: 0, y: 60 },
    width:       260,
    height:      42,
}));

UIImageButton — three modes

js
// 1. Image background + label (menu button with art)
import { UIImageButton } from "kernelplay-js"; // Assuming UIImageButton is exported from main library
new UIImageButton({ src: "./assets/btn.png", label: "Play" })

// 2. Icon only — label: null
new UIImageButton({ src: "./assets/settings_icon.png", label: null })

// 3. Sprite sheet states — different region per state
new UIImageButton({
    src: "./assets/btn_sheet.png",
    states: {
        normal:   { x: 0,   y: 0, w: 160, h: 60 },
        hover:    { x: 160, y: 0, w: 160, h: 60 },
        press:    { x: 320, y: 0, w: 160, h: 60 },
        disabled: { x: 480, y: 0, w: 160, h: 60 },
    }
})

UIBitmapText

js
import { UIBitmapText } from "kernelplay-js"; // Assuming UIBitmapText is exported from main library
const score = game.ui.add(new UIBitmapText({
    src:        "./assets/font.png",
    text:       "SCORE: 0",
    charWidth:  8,       // one char cell on sheet
    charHeight: 8,
    sheetCols:  16,      // chars per row on sheet
    charOffset: 32,      // ASCII 32 = space = first char
    scale:      3,       // render 3x bigger
    spacing:    1,
    anchor:     "topLeft",
    offset:     { x: 20, y: 20 },
    tint:       "#ffdd00",  // optional color tint
}));

// update text
score.setText(`SCORE: ${this.score}`);

// change tint at runtime
score.setTint("#ff0000");
score.clearTint();

World Space UI — label above an enemy

js
import { UIText } from "kernelplay-js"; // Assuming UIText is exported from main library

// screenSpace: false → position is in world coords, moves with camera
const nameTag = game.ui.add(new UIText({
    text:        "Boss",
    screenSpace: false,
    offset:      { x: enemy.transform.position.x, y: enemy.transform.position.y - 60 },
    style: { textColor: "#e74c3c", fontSize: 12 },
}));

// update world position every frame in your script
update(dt) {
    nameTag.offset.x = this.transform.position.x;
    nameTag.offset.y = this.transform.position.y - 60;
}

UIRaycast — skip game input when UI is hit

js
// In your game's input handling — check UI first
import { Mouse, MouseButton } from "kernelplay-js";
update(dt) {
    if (Mouse.wasPressed(MouseButton.Left)) {
        // don't fire game raycast if UI consumed the click
        if (game.ui.raycast.isUIAt(Mouse.x, Mouse.y)) return;

        const hit = this.raycast(worldPos.x, worldPos.y);
        if (hit) console.log("Hit:", hit.entity.name);
    }
}

Find elements by name

js
// find by name set in constructor
const btn = game.ui.find("UIButton");

// update it
btn.label   = "Restart";
btn.onClick = () => restartGame();

// remove it
game.ui.remove(btn);

// clear all UI
game.ui.clear();

Full HUD example — health + score + pause button

js
import { UIText, UIProgressBar, UIButton, UIPanel } from "kernelplay-js"; // Assuming these are exported from main library

class HUD {
    constructor(game) {
        this.ui = game.ui;

        // health bar
        this.healthBar = this.ui.add(new UIProgressBar({
            anchor: "topLeft",
            offset: { x: 20, y: 20 },
            width:  200,
            height: 18,
            style:  { progressFillColor: "#e74c3c" },
        }));

        // health label
        this.ui.add(new UIText({
            text:   "HP",
            anchor: "topLeft",
            offset: { x: 20, y: 48 },
            style:  { fontSize: 11, textColor: "#aaaacc", textAlign: "left" },
        }));

        // score
        this.scoreLabel = this.ui.add(new UIText({
            text:   "Score: 0",
            anchor: "topRight",
            offset: { x: 20, y: 20 },
            style:  { fontSize: 16, fontWeight: "bold", textAlign: "right" },
        }));

        // pause button
        const pauseBtn = this.ui.add(new UIButton({
            label:  "⏸",
            anchor: "topRight",
            offset: { x: 20, y: 60 },
            width:  40,
            height: 40,
            zIndex: 5,
        }));
        pauseBtn.onClick = () => game.paused = !game.paused;
    }

    update(player) {
        this.healthBar.setValue(player.health / player.maxHealth);
        this.scoreLabel.text = `Score: ${player.score}`;
    }
}

Anchor reference

text
"topLeft"       "topCenter"       "topRight"
"middleLeft"    "center"          "middleRight"
"bottomLeft"    "bottomCenter"    "bottomRight"

offset: { x, y } — pixel offset from that anchor point inward.

File structure

text
src/ui/
  index.js          ← single import for everything
  UICanvas.js       ← main manager, creates overlay canvas
  UITheme.js        ← global stylesheet
  UIElement.js      ← base class
  UIRaycast.js      ← separate input system
  UIElements.js     ← UIPanel, UIText, UIButton, UIImage,
                       UIProgressBar, UICheckbox, UISlider, UIInputField