An HTML/CSS HUD overlay
Status: Implemented (API 1.22). A HUD overlay written as an RmlUi document (RML markup and RCSS styles) with a data model the mod updates. The player places it in the HUD editor; it follows their Appearance. The complete mod is
sdk/examples/html_hud_lua.
Reference: HTML/CSS Overlays and Panels, rml, HUD Elements.
1. The files
mana_hud/
clight.mod.json
scripts/main.lua
assets/mana_hud/gui/mana.rml
assets/mana_hud/gui/mana.rcss
2. The document
data-model="mod" binds the document to the variables the mod declares. {{ }} shows a value, data-style-width sets a style from an expression, data-for repeats an element for every list entry and data-if shows one only sometimes.
<rml>
<head>
<link type="text/rcss" href="celestial:theme.rcss"/>
<link type="text/rcss" href="mana.rcss"/>
</head>
<body data-model="mod" class="cl-root">
<div class="box cl-hud-panel">
<div class="row">
<span class="cl-small">Mana</span>
<span class="value cl-small">{{ mana }} / {{ max }}</span>
</div>
<div class="track"><div class="fill" data-style-width="(mana / max * 100) + '%'"></div></div>
<div class="spells" data-if="spells.size > 0">
<span class="spell cl-small" data-for="s : spells" data-class-ready="s.ready">{{ s.name }}</span>
</div>
</div>
</body>
</rml>
celestial:theme.rcss gives cl-hud-panel and the text classes the player’s style: the rounded HUD panel and the UI font in Fancy, the translucent box and the game font in Vanilla. Your own sheet only does the layout:
.box { display: block; width: 100%; height: 100%; padding: 3px 4px; }
.track { display: block; height: 3px; margin-top: 2px; background-color: #00000080; }
.fill { display: block; height: 3px; background-color: #3FA9F5; }
.cl-fancy .fill { background-color: #7FC8FF; }
.spell { margin-right: 4px; color: #a0a0a0; }
.spell.ready { color: #ffffff; }
3. Open it as an overlay
local doc
cl.on("lifecycle.client_setup", function()
doc = cl.rml.open{
path = "assets/mana_hud/gui/mana.rml",
as_screen = false, -- a HUD overlay
id = "mana", label = "Mana bar", -- its name in the HUD editor
anchor = "bottom_left", x = 4, y = 4,
width = 110, height = 34,
model = { "mana", "max", "spells[]" },
}
doc:set("max", 20)
doc:set("mana", 20)
doc:set("spells", { { name = "Blink", ready = true }, { name = "Heal", ready = false } })
end)
The overlay is a HUD element of your mod: the player moves it, scales it and hides it in the HUD editor (it is listed under your mod’s name), and F1 hides it. It never takes input and draws under every screen.
4. Update only what changes
Set a value when it changes, not every frame: only the parts of the document bound to that variable update.
local mana, ticks = 20, 0
cl.on("tick.client_post", function()
ticks = ticks + 1
if ticks % 20 == 0 and mana < 20 then
mana = mana + 1
doc:set("mana", mana)
end
end)
5. What a document may load
Only files of your mod (relative to the document), resource ids for images (mana_hud:textures/gui/star.png) and celestial:theme.rcss. URLs, absolute paths, .., scripts and event attributes are refused when the document opens: cl.rml.open raises permission_denied with the reason. Logic stays in your mod: buttons in screens and panels call actions you list (actions = { "cast" }, data-event-click="cast('Heal')", on_action = function(doc, action, name) ... end).
6. The same document as a panel or a screen
Leave as_screen at true for a screen of its own, or pass parent = <one of your screens> with a box to show it as a panel inside that screen. Screens and panels take input; the data model and the actions work the same way.