Skip to content

HUD layers

Status: Partly implemented. Mod HUD layers with a render callback and an optional visibility test, removing them, and the status-bar heights. Mod layers are drawn after the whole vanilla HUD in registration order (above / below are stored but don’t interleave with vanilla layers yet), F1 hides them, and the heights are vanilla’s base value (39). Hiding or wrapping vanilla layers and visibility flags are Planned.

Function table: hud. Drawing functions: Screens, widgets and 2d drawing. For boxes the player can move, scale and hide in the HUD editor, use HUD elements (API 1.21). Guide: A HUD overlay. Client only.

Functions

typedef struct cl_hud_layer_desc {
    uint32_t          struct_size;
    cl_str            id;        // "ruby_tools:mana_bar"
    cl_str            above;     // a vanilla layer id ("minecraft:food"); stored for later ordering
    cl_str            below;
    cl_hud_render_fn  render;    // (cl_gui g, float partial_tick, void* user), RENDER
    cl_hud_visible_fn visible;   // optional (void* user) -> bool: skip render while false
    void*             user;
} cl_hud_layer_desc;
/* CL_HUD_LAYER_DESC_INIT */

cl_result cl_hud_layer_register(const cl_hud_layer_desc* desc, cl_hud_layer* out);
cl_result cl_hud_layer_remove(cl_hud_layer layer);
int32_t   cl_hud_left_height(void);    // height of the vanilla left status bars above the hotbar
int32_t   cl_hud_right_height(void);

Without registered layers the HUD hook costs one atomic load per frame.

Bindings

C C++ Lua
cl_hud_layer_register(&d, &l) clight::hud::add_layer("my_mod:info", [](clight::Gui g, float pt) { ... }, {.above, .below, .visible = [] { return true; }}) → Expected<HudLayer> cl.hud.register_layer{ id = "info", render = function(g, partial) ... end, visible = function() return true end }
cl_hud_layer_remove(l) layer.remove() (also frees the lambdas) layer:cancel()

The Lua id gets your mod id if it has no namespace; registering the same id again (a hot reload) replaces the old layer.

Example (Lua)

-- count once per tick, draw every frame
local text
cl.on("tick.client_post", function()
  local p = cl.entity.client_player()
  text = p and ("Rubies: " .. p:count_item("my_mod:ruby")) or nil
end)

cl.hud.register_layer{
  id = "rubies",
  visible = function() return text ~= nil end,
  render = function(g) g:text(text, 4, 4, 0xFFE0115F, true) end,
}

Vanilla layer ids

For above / below (ordering is planned): minecraft:crosshair, minecraft:hotbar, minecraft:experience_bar, minecraft:health, minecraft:armor, minecraft:food, minecraft:air, minecraft:status_effects, minecraft:boss_bars, minecraft:scoreboard_sidebar, minecraft:overlay_message, minecraft:title, minecraft:chat, minecraft:tab_list, minecraft:subtitles, minecraft:debug_overlay.

Planned

Interleaving mod layers with vanilla layers by above / below, hiding vanilla layers (to replace the hearts, for example), wrapping a vanilla layer (move or tint it), flags (hide in spectator, show in screens, hide with F3), and the real current status-bar heights.