HOOZiDocs
Skip to content

draw

Screen drawing. All draw.* calls go to the current frame's foreground draw list and must be called every render frame inside event.on("frame_update"). The draw list is reset every frame; missing a frame = a blank flicker on screen. See Getting Started.

Color parameter: throughout this page color is a number (32-bit packed color), built with draw.rgba / draw.u8 / draw.hex; you cannot pass an {r,g,b,a} table directly (the table form is only for ESP element palette opts).


Color Construction (returns packed uint32)

draw.rgba(r, g, b, a) → uint32 — floats 0..1

draw.u8(r, g, b, a) → uint32 — ints 0..255

draw.hex(packed : int) → uint32 — pass 0xRRGGBBAA directly


Color Transforms (in/out are packed uint32)

No new type; fully interoperable with rgba/u8/hex.

draw.color_mod_a(col, v) → uint32

Multiplies current alpha by v (0..1). Not an override — stacks well for fade-out animations.

lua
local half = draw.color_mod_a(red, 0.5)  -- alpha halved

draw.color_lerp(a, b, t) → uint32

Per-channel linear interpolation (alpha included). t is saturated to 0..1.

lua
-- Low health fades green → red
local hp_col = draw.color_lerp(draw.rgba(1,0,0,1), draw.rgba(0,1,0,1), hp / 100)

draw.color_darken(col, v) → uint32

RGB × (1-v), alpha preserved. v=0.5 → 50% darker.

draw.color_lighten(col, v) → uint32

RGB lerped toward 255 by v, alpha preserved. v=0.5 → halfway to white.

draw.color_hsv(h, s, v, a?) → uint32

HSV constructor. h ∈ [0,360) degrees (wraps via mod), s/v/a ∈ [0,1]. a defaults to 1.0.

lua
-- Rainbow cycle
local hue = (time.now() * 60) % 360
local rainbow = draw.color_hsv(hue, 1.0, 1.0)

Shapes

draw.line(x1, y1, x2, y2, color, opts?)

opts: {thickness = 1.0}

draw.rect(x1, y1, x2, y2, color, opts?)

opts: {filled = false, rounding = 0, thickness = 1, flags = 0}

draw.rect_gradient(x1, y1, x2, y2, c_tl, c_tr, c_br, c_bl)

A rectangle with one color per corner. Typical use: gradient health bars / gradient backgrounds.

draw.triangle_multicolor(x1, y1, c1, x2, y2, c2, x3, y3, c3)

Triangle with a different color per vertex; the GPU interpolates the fill. Useful for fade arrows and gradient hit markers.

draw.circle_multicolor(x, y, r, center_col, edge_col, opts?)

Radial gradient from center to edge (center one color, edge another, GPU interpolates). opts: {segments = 36}. Typical use: energy orbs, radar marker glows, minimap edge fades.

lua
-- A glowing orb: bright white center, transparent edge
local cy = draw.rgba(1, 0.9, 0.4, 0.9)
local cx = draw.rgba(1, 0.9, 0.4, 0)
draw.circle_multicolor(x, y, 30, cy, cx)

draw.circle(x, y, r, color, opts?)

opts: {filled = false, segments = 0, thickness = 1, fill = 1.0}

  • fill ∈ [0,1] — clockwise arc starting from 12 o'clock. fill = 1.0 (default) = full circle.
    • filled = true + fill < 1.0 → draws a pie (center → arc → center)
    • filled = false + fill < 1.0 → draws an open arc
    • Use for CD progress rings / loading spinners / radar sectors. fill = 1.0 takes ImGui's fast path with zero overhead.
lua
-- 75% progress ring
draw.circle(cx, cy, 30, draw.rgba(0.3,0.9,0.4,1),
            { fill = 0.75, thickness = 4 })

-- Filled pie wedge
draw.circle(cx, cy, 30, draw.rgba(1,0.6,0,0.4),
            { filled = true, fill = 0.5 })

draw.triangle(x1, y1, x2, y2, x3, y3, color, opts?)

opts: {filled = false, thickness = 1}. Suited for directional arrows, FOV triangle indicators, down arrows.

draw.quad(x1, y1, x2, y2, x3, y3, x4, y4, color, opts?)

opts: {filled = false, thickness = 1}. The core of projecting a 3D box: the top/bottom face becomes a 4-vertex quad after projecting the player's 8 world-space vertices to screen.

draw.polyline(points, color, opts?)

points: a point sequence, both forms are accepted

  • flat: {x1, y1, x2, y2, ...} (even length)
  • nested: { {x1, y1}, {x2, y2}, ... }

opts: {thickness = 1, closed = false, filled = false}

  • closed = true → last point connects back to the start
  • filled = true → uses AddConvexPolyFilled (reliable for convex polygons only); on the filled path, both closed and thickness are ignored

A universal fallback — can draw quads / projected box polygonal outlines / radar shapes / FOV arcs.


Shadow + Glow (composite helpers)

Pure pixel helpers — multiple stacked rings approximating soft blur, no shader required. The alpha channel of col is the baseline intensity; opts.alpha is a multiplier (0..1).

draw.shadow_line(x1, y1, x2, y2, color, opts?)

A projected shadow line. opts: {offset_x = 0, offset_y = 2, blur = 3, layers = 3, alpha = 1.0}

Larger blur → softer; more layers → smoother but more batches. offset_x/y is the shadow's offset relative to the original (mimics a light direction).

lua
-- A dark shadow under outlined text
draw.shadow_line(x, y + 12, x + w, y + 12,
                 draw.rgba(0, 0, 0, 0.6),
                 { offset_y = 1, blur = 2 })

draw.shadow_rect(x1, y1, x2, y2, color, opts?)

Rectangle outer shadow. opts: {spread = 6, rounding = 0, layers = 3, alpha = 1.0}

Spreads outward by spread pixels split into layers rings; inner ring almost opaque, outer rings fade out. Match rounding to your main rect's rounding. Higher layers = softer but more batches — default 3 is sufficient; keep it (or lower to 2) when batching ESP across many players.

lua
-- Drop shadow below an HP bar to improve contrast over menus
draw.shadow_rect(x, y, x + w, y + h,
                 draw.rgba(0, 0, 0, 0.5),
                 { spread = 4, rounding = 2 })
draw.rect(x, y, x + w, y + h, hp_col,
          { filled = true, rounding = 2 })

draw.glow_circle(x, y, r, color, opts?)

Circular outer glow. opts: {spread = 8, layers = 4, alpha = 1.0}

Spreads outward by spread pixels with a quadratic radial falloff (bright center, faded edge). Pairs well with circle for focus markers / warning lights. layers is the perf knob — default 4 with quadratic falloff keeps the batch count tractable across many player markers.

lua
-- Radar marker highlight: glow + filled core
draw.glow_circle(mx, my, 6, draw.rgba(1, 0.3, 0.3, 0.7))
draw.circle(mx, my, 4, draw.rgba(1, 0.3, 0.3, 1), { filled = true })

Text + Image

draw.text(x, y, color, text, opts?)

opts:

  • font — font handle from draw.font(name) (default = system font)
  • size — force font size float; omitted = ImGui::GetFontSize() (the currently-active font's size, not the font argument's default)
  • outline
    • true → theme dark-grey outline (project-uniform style)
    • uint32 color → custom outline color
    • omitted / false → no outline

Outline implementation = 4-direction 1px offset overlay, smooth and aliasing-free; more correct than scripting manual offset draw.text calls.

draw.image(tex_handle, x, y, w, h, opts?)

Parameters: tex_handle comes from file.image's :load / :svg / :create.

opts: {tint = uint32_white, uv0 = {0,0}, uv1 = {1,1}}

uv0 / uv1 must be array-style {u, v} tables — the {u=..., v=...} named form is not accepted.

draw.image_rotated(tex_handle, cx, cy, w, h, angle_deg, opts?)

Image rotated by angle_deg around (cx, cy). w/h are pre-rotation dimensions. opts: same as draw.image (tint / uv0 / uv1).

lua
-- Compass arrow follows player yaw
draw.image_rotated(arrow_tex, sw/2, sh/2, 32, 32, yaw_deg)

Clip Stack

draw.push_clip(x1, y1, x2, y2, intersect?)

Push a rectangular clip; subsequent draws are visible only inside the rect.

  • intersect defaults to true (intersect with current clip — safer for nested clipping)
  • Must be paired with pop_clip inside frame_update; the stack does not persist across frames.

draw.pop_clip()

Pop the most recently pushed clip rect.

lua
-- Progress bar mask (clip image to a fraction)
draw.push_clip(x, y, x + w * progress, y + h)
draw.image(icon, x, y, w, h)
draw.pop_clip()

Measurement

draw.measure(text, opts?) → w, h

opts: {font, size} — omitted = use the currently active font + ImGui::GetFontSize

draw.screen() → w, h

Current frame's screen resolution.


Fonts

Fonts are loaded at project startup (ImGui font atlas is built once); adding fonts at runtime is not supported — user fonts must be placed in res/fonts/ so they are auto-scanned at startup.

draw.fonts() → table<string>

Returns the list of available font names. 7 built-ins: "default" / "small" / "icon" / "logo" / "esp" / "loot" / "models", plus any .ttf/.otf files (without extension) scanned from res/fonts/.

draw.font(name) → Font | nil

Get a font handle; nil means the name does not exist.

Note: currently draw.font(name) only exposes the 7 built-in fonts ("default" / "small" / "icon" / "logo" / "esp" / "loot" / "models"); draw.fonts() will list additional .ttf/.otf filenames under res/fonts/, but actual handle lookup follows the built-in names (extra fonts have no handle yet — reserved for future extension).


Example

lua
event.on("frame_update", function(e)
    local sw, sh = draw.screen()
    local red    = draw.rgba(1.0, 0.2, 0.2, 1.0)
    local trans  = draw.u8(255, 255, 255, 90)

    -- Crosshair at screen center
    draw.line(sw/2 - 8, sh/2, sw/2 + 8, sh/2, red, { thickness = 2 })
    draw.line(sw/2, sh/2 - 8, sw/2, sh/2 + 8, red, { thickness = 2 })

    -- Top-left watermark (gradient background)
    draw.rect_gradient(10, 10, 200, 40,
        draw.rgba(0.1, 0.1, 0.15, 0.7), draw.rgba(0.2, 0.2, 0.3, 0.7),
        draw.rgba(0.2, 0.2, 0.3, 0.7), draw.rgba(0.1, 0.1, 0.15, 0.7))

    -- Outlined text (follows theme automatically)
    local big = draw.font("logo")
    draw.text(15, 18, draw.rgba(1, 1, 1, 1), "HELLO",
              { font = big, size = 24, outline = true })

    -- Directional arrow (pointing at a player)
    local cx, cy = sw/2, sh - 100
    draw.triangle(cx, cy - 12, cx - 10, cy + 8, cx + 10, cy + 8,
                  draw.rgba(1, 0.8, 0.2, 1), { filled = true })
end)

Animation composite (CD ring + color lerp + clip progress bar + rotated icon)

lua
local start_t = time.now()
event.on("frame_update", function(e)
    local t = (time.now() - start_t) % 4.0
    local progress = t / 4.0
    local sw, sh = draw.screen()

    -- CD ring (clockwise fill)
    local ring_col = draw.color_lerp(draw.rgba(0,0.9,1,1), draw.rgba(0.2,1,0.4,1), progress)
    draw.circle(120, 120, 36, ring_col, { fill = progress, thickness = 5 })

    -- Progress bar via clip mask
    local bar_x, bar_y, bar_w, bar_h = 80, 200, 240, 14
    draw.rect(bar_x, bar_y, bar_x + bar_w, bar_y + bar_h,
              draw.color_darken(ring_col, 0.7), { filled = true, rounding = 6 })
    draw.push_clip(bar_x, bar_y, bar_x + bar_w * progress, bar_y + bar_h)
    draw.rect(bar_x, bar_y, bar_x + bar_w, bar_y + bar_h,
              ring_col, { filled = true, rounding = 6 })
    draw.pop_clip()

    -- Rotated icon (requires a file.image:load handle)
    -- draw.image_rotated(spinner_tex, 300, 120, 32, 32, progress * 360)
end)