HOOZiDocs
Skip to content

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 identifier
  • fn : function(p : PlayerEntity, ctx : table) — invoked per player, return value is polymorphic:
fn returnsBehavior
stringtext element
number 0..1bar 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 table
    • label : string — default = id

    • colors : 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 element

    • kind : 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 via ctx.dl / draw.*; scenarios / dist / cleanup still 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 with table {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:

FieldTypeDescription
ctx.scenarioint0..3, determined by the system from player state
ctx.box{min=Vec2, max=Vec2}screen bounding box
ctx.distancenumberdistance (meters)
ctx.dlDrawListcurrent 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

lua
-- 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" })