Menus and HUD drawing
Plugin menu pages
samp.ui.menu.register(page)
Requires ui.menu. Registers a page, or replaces the page with the same ID. The function returns nothing. A malformed page or control is normally skipped; type errors and invalid numeric arguments can still raise a Lua error.
samp.ui.menu.register({
id = "main",
title = "Example",
controls = {
{ type = "switch", id = "enabled", title = "Enabled", value = true },
{
type = "dropdown",
id = "theme",
title = "Theme",
value = "dark",
options = {
{ value = "dark", label = "Dark" },
{ value = "light", label = "Light" }
}
}
}
})| Page field | Type | Rules |
|---|---|---|
id | string | Required, non-empty, at most 64 bytes. |
title | string | Required, non-empty, at most 128 bytes. |
controls | array | At most 32 controls; IDs must be unique on the page. |
A plugin may register at most 8 pages. Every control requires a non-empty type, id (maximum 64 bytes), and title (maximum 128 bytes). These common optional fields are available on every control:
| Field | Type | Default | Meaning |
|---|---|---|---|
description | string | "" | Supporting text, at most 512 bytes. |
enabled | boolean | true | Disabled controls remain visible but do not emit interaction events. |
visible | boolean | true | Hidden controls do not occupy layout and cannot emit interaction events. |
read_only | boolean | false | Read-only controls remain visible but do not emit interaction events. |
error | string | "" | Error text shown below the control, at most 512 bytes. |
Control types
The following is the complete API 1.1 control set. Lua uses snake_case field names; values are checked again when the host receives a change.
| Type | Additional fields and rules |
|---|---|
section | No additional fields. Renders a titled section and never emits an event. |
text | text: string, may be empty, maximum 512 bytes. Read-only display text; never emits an event. |
button | No additional fields. Activation emits valueType="action", value="click". |
switch | Required value: boolean. A change emits a boolean value. |
slider | min=0, max=1, step=0.1, value=min; all finite, magnitude at most 1,000,000, max > min, step > 0; the initial value is clamped and changes are normalized to the step. Emits a number. |
choice | value: string and options: 1–32 unique { value, label } entries. Values are at most 512 bytes, labels at most 128 bytes, and the current value must exist. Emits the selected value as a string. |
text_input | value="", placeholder="", max_length=512. max_length is an integer 1..512 measured in UTF-8 bytes; the value must fit. The host emits the string only after the user presses Apply. |
number_input | min=0, max=100, step=1, value=min; finite values with magnitude at most 1,000,000, max > min, step > 0, and the initial value inside the range. Apply emits a normalized number. |
dropdown | value: string plus 1–32 unique options entries. The current value must exist in the options; selecting one emits its value as a string. |
multi_choice | values: string[] (possibly empty) plus 1–32 unique options. Every selected value must exist and appear once. Tapping an option toggles it and emits the toggled option value as a string. |
color_picker | value: string in #RRGGBB or #RRGGBBAA form. Apply emits the validated color string. |
confirm_button | confirmation: string, at most 512 bytes. Activation first asks for confirmation, then emits the same action/click event. |
divider | No additional fields. Renders a separator and never emits an event. |
group | expanded: boolean, default true. Tapping emits action/toggle; the host uses it to show or hide following controls until the next group. |
list | options: 0–32 unique { value, label } entries; empty_text is optional and at most 512 bytes. Selecting an item emits its value as a string; an empty list shows empty_text. |
progress | value: number in 0..1 and optional indeterminate: boolean (default false). Display-only; never emits an event. |
For every selectable option, value is at most 512 bytes and label is at most 128 bytes. choice, dropdown, multi_choice, and list reject duplicate option values. A page replacement is atomic from the menu's point of view: controls that fail validation are not exposed.
ui.control_changed
Changes emit an event with pluginId, pageId, controlId, valueType, and typed value. The exact mapping is:
| Controls | valueType | value |
|---|---|---|
switch | boolean | true or false |
slider, number_input | number | The host-normalized finite value |
choice, dropdown, multi_choice, color_picker, text_input, list | string | Selected, toggled, submitted, or selected-item value |
button, confirm_button | action | "click" after activation/confirmation |
group | action | "toggle" |
section, text, divider, and progress do not emit control changes. Menu changes are delivered through the managed menu callback phase. See Event payloads for the common event envelope.
HUD phase
All samp.draw functions require ui.draw and may only be called synchronously inside draw.hud. They queue at most 512 draw commands per plugin per frame. They return nothing, except world_to_screen.
Colors are ARGB integers: 0xAARRGGBB. When normalized=true, coordinates use the 0..1 display range; otherwise they are screen coordinates. General coordinates must be finite with magnitude at most 100,000.
samp.draw.text(options)
| Field | Default | Rules |
|---|---|---|
x, y | 0 | Coordinates. |
text | — | Required string, maximum 1,024 bytes. |
size | 16 | Finite, > 0 and <= 512. |
color | 0xFFFFFFFF | ARGB. |
normalized | false | Boolean. |
samp.draw.line(options)
Fields: x1=0, y1=0, x2=0, y2=0, color=0xFFFFFFFF, thickness=1 (>0..100), and normalized=false.
samp.draw.rect(options)
Same as line, plus filled=false. thickness remains required to be valid even for a filled rectangle.
samp.draw.circle(options)
Fields: x=0, y=0, radius=1, color=0xFFFFFFFF, filled=false, thickness=1 (>0..100), and normalized=false. Radius must be positive and at most 100,000; in normalized mode it must be at most 1.
samp.draw.progress_bar(options)
Fields: x1=0, y1=0, x2=0, y2=0, value=0, color=0xFFFFFFFF, background_color=0x66000000, and normalized=false. x2 > x1, y2 > y1, and value is in 0..1.
samp.draw.image(options)
| Field | Default | Rules |
|---|---|---|
x1, y1, x2, y2 | 0 | x2 > x1, y2 > y1. |
resource | — | Required safe package-relative image path, maximum 256 bytes. |
alpha | 1 | Finite 0..1. |
normalized | false | Boolean. |
Supported formats are PNG, WebP, JPEG, and JPG. A source file is at most 16 MiB; decoded dimensions are at most 1024×1024. Each plugin may cache 16 images and 16 MiB of decoded image data; the runtime-wide decoded budget is 64 MiB. At most one previously uncached image begins loading per frame.
samp.draw.world_to_screen(position)
Accepts Vector3. Returns nil when the game is unavailable or the point cannot be projected in front of the camera. Otherwise returns:
{
x = number,
y = number,
depth = number,
width = number,
height = number
}