Skip to main content
The esp module is a declarative layer for drawing overlays on entities. You never touch on("render", ...) - instead you register elements on an entity class, and each frame the engine calls your render(e, ctx) function per entity to decide what to draw. The user controls where and how elements are styled via the in-game builder menu; your code only decides what they show and when they are visible.

Overview

Classes

Pick which entities to draw on: enemy, team, dropped, projectile.

Elements

Register text, bars, and icons with a per-frame render.

Render returns

Shortcuts and descriptor objects your render can return.

Runtime control

Mutate element visibility, label, and preview on the fly.

Classes

A class is a group of entities the engine iterates for you. You attach elements to it and they are drawn on every matching entity.

esp.class


Creates the class, or returns the existing one if it was already created with the same kind. This makes the call idempotent - safe to run on every script reload without duplicating elements.
"enemy" | "team" | "dropped" | "projectile"
required
Which entities to iterate every frame.
  • enemy - enemy player pawns
  • team - teammate player pawns (not including local)
  • dropped - dropped weapons and grenades
  • projectile - in-flight grenades, molotovs, smokes
(e: Entity) => any
Runs once per entity per frame, before any element’s render. Its return value is passed as ctx to every element on that entity. Use it to hoist shared work like HP parsing, alive checks, or distance math so the element renders stay cheap.
You can replace context at any time without re-registering elements:

The render callback

Every element takes a render(e, ctx) function. It runs every frame for every entity of the class.
Entity
The entity currently being drawn. This is the exact same proxy documented in Entities - all schema fields, reserved properties (isValid, className, controller, …), helper methods (getBoundingBox, isEnemy, …) and raw-buffer reads are available.
any
Whatever the class’s context(e) returned for this entity on this frame. If no context was supplied, ctx is undefined. Shared across every element on the same entity, so do heavy/shared work once in context rather than re-doing it in each render.

Elements

A class has three element factories. Each returns an Element handle.

class.text


Registers a text element drawn on every entity of the class.
string
required
Stable ID. Used as the key in the user’s saved layout - keep it constant across reloads or the user will lose their placement.
(e: Entity, ctx: any) => TextResult
required
Called every frame for every entity. See Text result for accepted return shapes.
TextResult
Value shown in the builder menu before a real entity is available. Accepts the same shapes as render.
"top" | "bottom" | "left" | "right" | "center"
Initial slot for the element. The user can drag it elsewhere; this is only the first-time default.

class.bar


Registers a bar element (health, armor, progress, etc.). Same fields as class.text. The render return type is a Bar result.

class.icon


Reserved for future use. Always return null from render for now.

Render returns

Every render (and preview) return value is one of three things:
Fields you return override the user’s menu settings for that frame. Fields you omit keep whatever the user configured. There is no “clear override” call - stop returning the field and the user’s value takes over on the next frame.

Text result


Bar result


Icon result

Reserved. Always return null.

Preview

preview is shown in the builder menu so the user can see the element before a real entity exists. It accepts the same shapes as render.
Make preview look like a realistic render output. If the real element shows HP 100, don’t set preview: "X" - the user can’t judge size / position from it.

Runtime control

Every .text / .bar / .icon call returns an Element handle for live mutation.

element.destroy


Permanently removes the element. Idempotent - safe to call multiple times, including after a previous destroy(). After destruction:
  • getters return "" / false
  • setters are silently ignored
  • no exceptions are ever thrown
Idempotent destroy makes esp safe for hot-reload flows: re-running the script simply re-registers everything without leaking elements.

Error handling

Exceptions inside render and context are caught by the bridge so one broken function never takes down the rest.

Recipes

Enemy HP ESP with critical-state color

Teammates — name + value-gradient HP bar

Distance text — only within range

Toggle an element with a keybind

Dropped weapons — name label