Themed GUIs, HUD elements and appearance pages
Lesson 14.9
Players choose how Celestial looks in Appearance: the Vanilla style (the game’s own widgets) or the Fancy style (the Celestial design), and a colour theme. With the UI kit your screens, your HUD parts and your settings follow that choice by themselves. You write them once; the player sees them in their style.
This lesson builds the three parts of a small compass mod. The whole mod is in the SDK as sdk/examples/ui_kit_lua.
A themed screen
Add themed = true to a screen and use kit widgets:
local function open_settings()
cl.screen.open{
title = "Compass Plus",
pause = false,
themed = true,
init = function(s)
local x, y = s:width() // 2 - 150, 30
s:panel(x - 14, y - 14, 328, 210)
s:heading(x, y, "Compass Plus", 1)
s:toggle(x, y + 30, 300, 20, "Show the compass bar", true, function(t)
print("show: " .. t:value()) --> show: 0 (after a click)
end)
s:slider(x, y + 56, 300, 20, "Bar width", 80, 240, 160, 10, function(w)
print("width: " .. w:value())
end)
s:dropdown(x, y + 86, 300, 20, "Labels", "Letters\nDegrees", 0, function(d)
print("labels: " .. d:text()) --> labels: Degrees
end)
s:button(x + 210, y + 160, 90, 20, "Done", function() s:close() end)
end,
}
end
Open it and switch Appearance > Style between Vanilla and Fancy while it is open: the same screen redraws in the other style at once. In Vanilla the toggle is a button reading “Show the compass bar: ON” and the dropdown cycles through its choices when you click; in Fancy they are a switch and a field with a list.
The kit has toggle, icon_button, dropdown, tabs, list, panel, card, heading and color_picker, plus the widgets you already know (button, checkbox, slider, text_field, label). The UI Kit lists every argument.
A list
local list = s:list(x, y, 220, 120, 24, function(l)
print("picked row " .. l:value()) --> picked row 2
end)
list:list_add("Home", "214 m north-west", "marker")
list:list_add("Death point", "38 m south", "warning")
The third argument of list_add is an icon name ("marker", "world", "star" …) or your own GUI sprite as "my_mod:waypoint".
Your own drawing in the right style
In a themed screen’s render, the drawing context knows the style too. Use the themed functions and your drawing matches the widgets:
render = function(s, g, mx, my)
g:panel(10, 10, 120, 40)
g:ui_text("Distance", 18, 16, "small", 0) -- 0: the style's own colour
g:ui_text("214 m", 18, 28, "h3", 0)
end,
cl.ui.fancy() tells you the style when you need to decide something yourself, and cl.ui.color("panel") or cl.ui.length("radius.box") give the theme’s values (Theme Tokens).
A HUD element
A HUD layer draws wherever you say. A HUD element is a box the player moves, scales and hides in the HUD editor:
local heading = 0
local bar = cl.hud.element_register{
id = "compass", label = "Compass bar", icon = "marker",
width = 160, height = 14, anchor = "top", x = 0, y = 6,
panel = true, cached = true,
render = function(g, w, h)
g:ui_text(tostring(heading), w / 2 - 6, 2, "small", 0)
end,
}
cl.on("tick.client_post", function()
local yaw = math.floor(cl.entity.client_player():rotation().yaw) % 360
if yaw ~= heading then
heading = yaw
bar:invalidate() -- draw it again with the new number
end
end)
render(g, w, h)draws inside the element’s own box, from(0, 0).panel = trueputs the Fancy HUD panel behind it.cached = truekeeps the last drawing: the game replays it every frame and callsrenderagain only afterinvalidate(). Your mod costs almost nothing while the player stands still.
Open the HUD editor (Appearance > HUD > Open HUD Editor): “Compass bar” is listed under From mods, and you can drag it.
An Appearance page
Settings that change how your mod looks belong in Appearance > Mods. A page shows rows bound to your client config:
local config = cl.config.open("client")
config:define_bool("bar.show", true)
config:define_i32("bar.width", 160, 80, 240)
config:define_str("bar.labels", "Letters")
cl.on("lifecycle.client_setup", function()
local page = cl.ui.page_register{
id = "settings", label = "Compass Plus", icon = "marker",
on_change = function(page, key) bar:invalidate() end,
}
page:option("bar.show", "Show the compass bar", "")
page:option("bar.width", "Bar width", "Width in GUI pixels")
page:choice("bar.labels", "Labels", "", "Letters\nDegrees")
page:hud_element(bar)
end)
The player edits the values like any other setting; they are saved in your config file and config:get_* returns them.
Try it
Add a Look tab to the settings screen with a colour picker for the compass marker. Save the colour in the client config as "#RRGGBB" and show the same option on the Appearance page.
Show a solution
config:define_str("bar.marker", "#FFAA00")
-- in init: a tabs widget whose second page holds the picker
local c = tonumber(config:get_str("bar.marker"):sub(2), 16)
local picker = s:color_picker(x, y + 30, 300, 20, "Marker colour", c, function(p)
config:set_str("bar.marker", string.format("#%06X", math.floor(p:value()) & 0xFFFFFF))
config:save()
bar:invalidate()
end)
local general = s:toggle(x, y + 30, 300, 20, "Show the compass bar", true, function() end)
picker:set_visible(false)
s:tabs(x, y, 300, 20, "General\nLook", 0, function(t)
general:set_visible(t:value() == 0)
picker:set_visible(t:value() == 1)
end)
-- on the Appearance page
page:color("bar.marker", "Marker colour", "The centre marker")
Recap: themed = true + kit widgets for screens, g:panel / g:ui_text for your own drawing, cl.hud.element_register{...} for HUD parts the player places, cl.ui.page_register{...} for an Appearance page.