A client mod like the built-in client settings features
Status: Implemented for a client-only mod with a config page, a HUD effect and a keybind. This guide uses the Mods screen’s Config page and a HUD layer. A page in the client’s Appearance screen (Appearance Pages), HUD elements the player can move (HUD Elements) and per-entity render parameters (Post Processing and Camera) are covered on their own pages.
Celestial ships built-in client features in its Client Settings screen (FullBright, block outline, item physics, shield indicators, …). This guide builds a feature of the same kind as a mod, Low Health Warning: a red edge on the screen when health is low, with a toggle key, off by default, and zero cost while off.
Language: Lua. side: client, sync: client_only. APIs: Client integration (mods screen, client settings, toasts, camera), HUD layers, Configuration.
1. Manifest
{
"schema": 1, "id": "low_health", "version": "1.0.0", "name": "Low Health Warning", "license": "MIT",
"api": 1, "side": "client", "sync": "client_only",
"runtime": { "type": "lua", "entry": "scripts/main.lua" }
}
client_only means it works on any server: vanilla, Paper, and older versions through the compat layer.
2. Options: off by default
local config = cl.config.open("client")
config:define_bool("enabled", false)
config:comment("enabled", "Show a red edge when health is low")
config:define_i32("threshold", 6, 1, 19)
config:comment("threshold", "Health (in half hearts) below which the edge shows")
Off by default is the rule for visual tweaks: installing the mod alone must not change the image. The player opts in on the Config page.
3. The effect exists only while enabled
local tick_sub, hud, low = nil, nil, false
local function set_active(on)
if on and not tick_sub then
tick_sub = cl.on("tick.client_post", function()
local p = cl.entity.client_player()
low = p ~= nil and p.health < config:get_i32("threshold")
end)
hud = cl.hud.register_layer{
id = "edge",
visible = function() return low end,
render = function(g)
local w, h = g:width(), g:height()
g:fill_gradient(0, 0, w, 12, 0x60FF0000, 0x01FF0000)
g:fill_gradient(0, h - 12, w, h, 0x01FF0000, 0x60FF0000)
end,
}
elseif not on and tick_sub then
tick_sub:cancel(); tick_sub = nil
hud:cancel(); hud = nil
low = false
end
end
set_active(config:get_bool("enabled"))
config:on_reload(function() set_active(config:get_bool("enabled")) end)
Colours are 0xAARRGGBB; an alpha of 00 counts as opaque, so the fade ends at 01. While the option is off there is no tick handler and no HUD layer: the mod costs nothing.
4. A toggle key
local key
cl.on("lifecycle.client_setup", function()
key = cl.keybind.register{ id = "low_health:toggle", default_key = "key.keyboard.unknown", label = "Toggle low health warning" }
end)
cl.on("tick.client_post", function()
if not key then return end
while key:consume_click() do
local on = not config:get_bool("enabled")
config:set_bool("enabled", on)
config:save()
set_active(on)
cl.client.action_bar(on and "Low health warning on" or "Low health warning off")
end
end)
Unbound by default (key.keyboard.unknown): the player picks a key in Controls.
5. Checklist (the bar the built-in features meet)
- [ ] Off by default; no visible change until the player enables it.
- [ ] Zero cost while off (no subscriptions, no layers).
- [ ] Work done per tick, not per frame; the frame only draws.
- [ ] Works on any server (
client_only).
Planned
A category in the Client Settings screen with a live preview, render hooks (entity tints, outlines), and camera and FOV events.