esp
ESP element registration. Each ESP element has 4 independent palettes (one per scenario: INV / VIS / DWN / ALLY); the system picks one automatically per player state. Scripts read esp.scenario for the current preview scenario, use el:set_color(value, scenario) to change a single scenario, or el.colors = {c0,c1,c2,c3} to batch-set all four in one line.
esp.add(id, fn, opts?) → ESPElement
Parameters
id : string— unique element identifierfn : function(p : PlayerEntity, ctx : table)— invoked per player, return value is polymorphic:
fn returns | Behavior |
|---|---|
string | text element |
number 0..1 | bar element |
table {text=, text_color=, bar=, bar_color=} | mixed |
nil (already drawn via ctx.dl) | free drawing |
nil (nothing drawn) | the player is not displayed |
opts?— optional tablelabel : string— default = idcolors : table— 4-element{c_inv, c_vis, c_dwn, c_ally}, each ={r,g,b,a}dist : table—{min_m, max_m}settings : function(group : Groupbox)— callback for adding extra controls to this elementkind : string—"text"(default) /"bar"/"mixed"/"free", controls slot-drag behavior:"text"→ 6 slots (top / top-left / bottom-left / top-right / bottom-right / bottom)"bar"→ 4 slots (top / middle-left / middle-right / bottom)"mixed"→ 4 bar slots (strictest constraint; fn returns text + bar simultaneously)"free"→ not registered in the slot UI (no drag handle); user fully draws viactx.dl/draw.*;scenarios/dist/cleanupstill apply; fn return value is arbitrary (the slot system does not consume it).
Must match the fn return type:
"text"pairs with string /table.text;"bar"pairs with number /table.bar;"mixed"pairs withtable {text=, bar=};"free"does not consume the fn return value (user draws). Unrecognized values trigger a LOG_WARN and fall back to"text".
ctx fields:
| Field | Type | Description |
|---|---|---|
ctx.scenario | int | 0..3, determined by the system from player state |
ctx.box | {min=Vec2, max=Vec2} | screen bounding box |
ctx.distance | number | distance (meters) |
ctx.dl | DrawList | current frame's foreground draw list (required when kind="free") |
esp.find(id) → ESPElement | nil
esp.remove(id)
esp.elements : map<id, ESPElement> (iterable via pairs)
esp.scenario : int (read-only)
esp.INV / esp.VIS / esp.DWN / esp.ALLY = 0 / 1 / 2 / 3
ESPElement Methods / Fields
el:get_color(scenario?) → table<r,g,b,a> / el:set_color(value, scenario?)
Omitting scenario = current scenario.
el:get_enabled(scenario?) → bool / el:set_enabled(value, scenario?)
el.colors = {c0, c1, c2, c3}
Set all 4 scenario colors at once.
el.enableds = {b0, b1, b2, b3}
Set all 4 scenario enabled flags at once.
el.dist : table = {min_m, max_m}
el.label : string
Example
-- Text element: return a string
esp.add("tag", function(p, ctx)
if p.is_teammate then return "ALLY" end
if p.is_visible then return "VIS" end
return "INV"
end, {
label = "Tag",
kind = "text",
colors = {
{ 0.85, 0.85, 0.85, 1.0 }, -- INV
{ 1.00, 0.35, 0.35, 1.0 }, -- VIS
{ 1.00, 0.80, 0.20, 1.0 }, -- DWN
{ 0.35, 0.85, 1.00, 1.0 }, -- ALLY
},
dist = { 5.0, 300.0 },
})
-- Bar element: return 0..1
esp.add("hp_bar", function(p, ctx)
local total = (p.health or 0) + (p.shield or 0)
return total / 200.0
end, { kind = "bar" })
-- Free drawing: draw via ctx.dl, fn returns nil
esp.add("crosshair", function(p, ctx)
local cx, cy = (ctx.box.min.x + ctx.box.max.x) * 0.5, ctx.box.min.y - 10
draw.line(cx - 5, cy, cx + 5, cy, draw.rgba(1, 0, 0, 1))
return nil
end, { kind = "free" })