HP Bar from GMCP
On a GMCP server, vitals arrive as data, with no prompt parsing. This renders them as a block graph docked above the input line:
local vitals = {}
rune.gmcp.subscribe("Char")rune.gmcp.on("Char.Vitals", function(data) vitals = data rune.ui.refresh_bars() -- render now, don't wait for the tickend)
local function blocks(cur, max, width, color) local filled = max > 0 and math.floor(width * cur / max + 0.5) or 0 return color(string.rep("█", filled)) .. rune.style.gray(string.rep("░", width - filled))end
rune.ui.bar("vitals", function(width) local hp, mhp = tonumber(vitals.hp), tonumber(vitals.maxhp) if not (hp and mhp) then return "" end local sp, msp = tonumber(vitals.sp) or 0, tonumber(vitals.maxsp) or 1 local hp_color = hp < mhp * 0.25 and rune.style.red or rune.style.green return string.format("HP %s %d/%d SP %s %d/%d", blocks(hp, mhp, 14, hp_color), hp, mhp, blocks(sp, msp, 10, rune.style.cyan), sp, msp)end)
rune.ui.layout({ bottom = { "vitals", "input", "status" } })How it works
Section titled “How it works”- The GMCP handler stores the data and calls
refresh_bars(); the render function only formats. Keep that split, since renderers run four times a second. subscribe("Char")asks the server for the wholeCharpackage.- The layout line matters: a bar shows only if a layout dock names it.
- The bar turns red under 25% HP by swapping the style function.
Variations
Section titled “Variations”- Without GMCP, feed
vitalsfrom a prompt trigger instead:rune.trigger.regex("^HP:(\\d+)/(\\d+)", ...). The bar code doesn’t change. - Field names (
sp/maxsphere) vary by game;/gmcpand the catch-all"gmcp"hook show what yours sends.
Related: Bars · GMCP · Layout & UI