Skip to content

SharpGfx Lua API

SharpGfx is the project's immediate-mode UI library. Lua modules can use it through either the global sgfx table or game.ui; require("sharpgfx") returns that same table.

UI functions are valid only inside a game.on("render", ...) callback. Calls outside a render callback are safe but return defaults and do not draw. Render subscriptions are removed automatically when their module is stopped or reloaded.

Four commented examples are included:

  • scripts/ui_01_basic_window.lua — the smallest useful window.
  • scripts/ui_02_widget_gallery.lua — common controls, layout, colors, popups, and the Lua editor.
  • scripts/ui_03_draw_canvas.lua — draw lists and an interactive canvas.
  • scripts/ui_04_imgui_demo.lua — a large, searchable demo modeled after imgui_demo.cpp, including tables, menus, inputs, plots, queries, and example windows.

Minimal correct window

lua
-- @type module
local ui = require("sharpgfx")
local open = true
local enabled = false
local power = 50

game.on("render", function()
  ui.set_next_window_size(420, 260, ui.condition.appearing)

  local visible
  visible, open = ui.begin("My Lua Window", open)
  if visible then
    ui.text_colored(ui.color(242, 194, 15), "Built entirely from Lua")
    ui.separator()

    local changed
    changed, enabled = ui.checkbox("Enabled", enabled)
    changed, power = ui.slider_int("Power", power, 0, 100)
    if ui.button("Run action", 120, 28) then print("Lua UI action") end
  end

  -- begin() always creates a scope, even when visible is false.
  ui.finish()
end)

The first result of a stateful control is normally changed; the remaining result or results are the updated value. Lua owns those values and should pass them back on the next frame. combo, list_box, table columns, font indices, and plot offsets use Lua's 1-based indexing.

Runtime helpers are is_rendering(), time(), delta_time(), framerate(), and display_size(). The last returns width, height; time values are seconds.

Overlay lifecycle and host window

Overlay controls are available as both game.overlay and require("sharpgfx").overlay. Unlike drawing functions, these controls are safe from tick, key, packet, MCP, and render callbacks.

FunctionBehavior
visible()Returns whether the overlay is currently shown.
show()Shows the main overlay again.
hide() / close() / minimize()Hides every overlay surface, including Community Store and Lua render windows.
toggle()Toggles the complete overlay. This is the same lifecycle used by Insert.
maximized()Returns whether the main menu is maximized.
maximize() / restore() / toggle_maximized()Controls the main menu's maximized state and shows it.
position() / size()Return the main menu's current x, y or width, height.
set_position(x, y) / set_size(width, height)Schedule a new main-menu position or size. Setting either restores a maximized menu first.
mouse_captured()True only while the cursor is over an overlay window and native game input is being blocked.
community_store_open() / close_community_store()Query or close the Community Store surface.
overlay_controls(id?)Renders reusable Minimize, Maximize/Restore, and Close buttons for the complete host overlay. Call after a successful begin().
lua
-- These calls do not need to run inside game.on("render").
game.overlay.set_position(80, 60)
game.overlay.set_size(1100, 700)
game.overlay.show()

-- Inside a Lua window render callback:
ui.overlay_controls("my_window")

Scope rules

SharpGfx repairs leaked stacks at the end of a Lua render callback, but that is a safety net rather than a programming pattern. Balance scopes explicitly:

BeginMatching endRule
beginfinishAlways call finish, including when visible is false.
begin_childend_childAlways end a child created in a valid parent.
begin_group_scopeend_group_scopeAlways balanced.
begin_disabledend_disabledAlways balanced.
begin_tableend_tableCall end_table only when begin returned true.
begin_menu_bar / begin_main_menu_barcorresponding endEnd only when begin returned true.
begin_menu, begin_combo, begin_list_boxcorresponding endEnd only when begin returned true.
begin_popup, begin_popup_modal, begin_tooltipcorresponding endEnd only when begin returned true.
begin_tab_bar, begin_tab_itemcorresponding endEnd only when begin returned true.
tree_nodetree_popPop an open node unless no_tree_push_on_open was used.

Windows and children

FunctionReturns / behavior
begin(name, open?, flags?)visible, open; always pair with finish().
finish()Ends the current window. It is named differently from ImGui's End because end is a Lua keyword.
begin_child(id, width?, height?, border?, flags?)visible; always pair with end_child().
end_child()Ends the current child.
set_next_window_pos(x, y, condition?)Sets position for the next window.
set_next_window_size(width, height, condition?)Sets size for the next window.
set_next_window_size_constraints(min_w, min_h, max_w, max_h)Constrains the next window. Zero disables that bound.
window_pos() / window_size()Return x, y and width, height.
window_width()Current window width.
set_window_pos(x, y) / set_window_size(w, h)Schedules a coherent position/size change for the current window's next frame.
window_appearing()True on the first visible frame.
window_hovered() / window_focused()Current window state.
set_mouse_cursor_visible(visible)Enables or disables the software cursor.

flags (also available as window_flags) contains none, no_title_bar, no_resize, no_move, no_scrollbar, no_background, no_inputs, child_window, popup, modal, and menu_bar. A regular window must include flags.menu_bar before begin_menu_bar() can succeed.

condition contains always and appearing.

Text and separators

FunctionBehavior
text(value)Plain text.
text_disabled(value)Text using the disabled color.
text_colored(color, value)Packed-color text.
text_wrapped(value)Text wrapped to the available region.
label_text(label, value)Label/value row.
bullet()Standalone bullet; normally followed by same_line() and another item.
bullet_text(value)Bullet and text in one call.
separator()Horizontal separator.
separator_text(label)Labeled separator.
new_line() / spacing()Vertical layout helpers.
align_text_to_frame_padding()Aligns the next text baseline with framed widgets.

All Lua strings are passed as data, not as native format strings, so % characters are safe.

Buttons and selection

FunctionReturns
button(label, width?, height?)pressed
small_button(label)pressed
arrow_button(id, direction)pressed; use dir.left, right, up, or down.
invisible_button(id, width, height)pressed
checkbox(label, value)changed, value
checkbox_flags(label, flags, mask)changed, flags
toggle(label, value)changed, value
radio_button(label, active)pressed
selectable(label, selected?, flags?, width?, height?)pressed

selectable_flags contains none, allow_double_click, span_all_columns, and disabled.

Numeric widgets

Scalar controls return changed, value:

text
slider_float(label, value, minimum, maximum, format?)
slider_int(label, value, minimum, maximum)
drag_float(label, value, speed?, minimum?, maximum?, format?)
drag_int(label, value, speed?, minimum?, maximum?, format?)
input_float(label, value, step?, fast_step?, format?)
input_int(label, value, step?, fast_step?)

Two-, three-, and four-component controls receive components as separate arguments and return changed followed by every updated component:

text
slider_float2 / slider_float3 / slider_float4
slider_int2   / slider_int3   / slider_int4
drag_float2   / drag_float3   / drag_float4
drag_int2     / drag_int3     / drag_int4
input_float2  / input_float3  / input_float4
input_int2    / input_int3    / input_int4

Float slider vector forms take label, components..., minimum, maximum, format?; integer sliders omit the format. Drag vector forms take label, components..., speed?, minimum?, maximum?, format?. Float input vector forms take label, components..., format?; integer input vector forms take only the label and components.

Text input and editor

FunctionReturns
input_text(label, value, capacity?)changed, value
input_text_hint(label, hint, value, capacity?)changed, value
input_text_multiline(label, value, width?, height?, capacity?)changed, value
lua_editor(id, source, width?, height?)changed, source, save_requested; Ctrl+S requests a save.

Capacities are clamped to a safe range and expanded when needed to preserve the supplied string.

Combos, list boxes, trees, tabs, and colors

FunctionReturns / behavior
combo(label, selected, items)changed, selected; items is an array of strings.
set_next_combo_height(height)Sets the next combo popup height.
begin_combo(label, preview) / end_combo()Custom combo scope.
list_box(label, selected, items, height_items?)changed, selected.
begin_list_box(label, width?, height?) / end_list_box()Custom list-box scope.
collapsing_header(label, flags?)open.
set_next_item_open(open, condition?)Controls the next tree/header's open state.
tree_node(label, flags?) / tree_pop()Tree scope.
tree_push(id?) / tree_pop()Manual tree indentation and ID scope.
begin_tab_bar(id, flags?) / end_tab_bar()Tab-bar scope.
begin_tab_item(label, open?, flags?)visible, open; end a visible tab with end_tab_item().
color_edit(label, r, g, b, a?)changed, r, g, b, a; components are 0..1.
color_button(id, packed_color, width?, height?)pressed.

tree_flags contains none, default_open, framed, leaf, bullet, no_tree_push_on_open, and span_available_width (span_avail_width is an alias). tab_bar_flags contains none; tab_item_flags contains none and set_selected.

Progress and plots

FunctionBehavior
progress_bar(fraction, width?, height?, overlay?)Draws a 0..1 progress value.
plot_lines(label, values, offset?, overlay?, scale_min?, scale_max?, width?, height?)Line plot from a numeric Lua array.
plot_histogram(label, values, offset?, overlay?, scale_min?, scale_max?, width?, height?)Histogram from a numeric Lua array.

Plot offsets are 1-based and wrap safely. An empty or nonnumeric sample array is handled without reading invalid memory.

Tables

Tables are the preferred way to build columns. They support column sizing, resizable separators, headers, horizontal and vertical borders, alternating row backgrounds, row/cell colors, explicit row heights, and direct column navigation.

lua
local flags = ui.table_flags.borders + ui.table_flags.row_bg + ui.table_flags.resizable
if ui.begin_table("inventory", 3, flags, 0, 180) then
  ui.table_setup_column("Item", ui.table_column_flags.width_stretch)
  ui.table_setup_column("Count", ui.table_column_flags.width_fixed, 70)
  ui.table_setup_column("Price", ui.table_column_flags.width_fixed, 70)
  ui.table_headers_row()

  for _, row in ipairs(rows) do
    ui.table_next_row()
    ui.table_next_column(); ui.text(row.name)
    ui.table_next_column(); ui.text(tostring(row.count))
    ui.table_next_column(); ui.text(tostring(row.price))
  end
  ui.end_table()
end
FunctionBehavior
begin_table(id, columns, flags?, outer_w?, outer_h?, inner_width?)Starts a 1..64-column table and returns visible; outer_h is a minimum height (the table grows for its rows), and invalid counts return false.
end_table()Ends a visible table.
table_setup_column(label, flags?, initial_width?, user_id?)Configures the next column before the first row.
table_header(label)Draws one custom header cell inside a headers row.
table_headers_row()Emits a header row from setup labels.
table_next_row(row_flags?, minimum_height?)Advances to a new row.
table_next_column()Advances to the next column and returns whether it is visible.
table_set_column(index)Selects a 1-based column and returns whether it is visible.
table_column_index() / table_row_index()Current 1-based indices.
table_column_count()Number of columns.
table_active()True while inside a table scope.
table_column_name(index?)Name of the current or selected 1-based column.
table_column_width(index?)Width of the current or selected 1-based column.
table_set_bg_color(target, color, column?)Sets a row or cell background; column is 1-based.

table_flags contains none, resizable, row_bg, borders_inner_h, borders_outer_h, borders_inner_v, borders_outer_v, borders_h, borders_v, borders, sizing_fixed_fit, and sizing_stretch_same.

table_column_flags contains none, width_stretch, width_fixed, and no_resize. table_row_flags contains none and headers. table_bg_target contains none, row_bg0, row_bg1, and cell_bg.

Flags are integer bit masks. Combine independent flags with + or Lua's bitwise | operator.

FunctionReturns / behavior
begin_menu_bar() / end_menu_bar()Menu bar inside a window created with flags.menu_bar.
begin_main_menu_bar() / end_main_menu_bar()Screen-level main menu bar.
begin_menu(label, enabled?) / end_menu()Nested menu scope.
menu_item(label, shortcut?, selected?, enabled?)clicked, selected; passing a selected value makes it toggleable.
open_popup(id)Opens a popup for the matching begin_popup call, including in the same frame.
begin_popup(id) / end_popup()Regular popup scope.
begin_popup_modal(id, open?)visible, open; end only when visible.
begin_popup_context_item(id?, button?)Opens a context popup for the last item; right mouse by default.
begin_popup_context_window(id?, button?)Opens a context popup for the current window.
popup_open(id)Reports whether a named popup is open.
close_popup()Closes the current popup.
tooltip(text)One-call tooltip for the most recent item.
begin_tooltip() / end_tooltip()Custom tooltip contents.

Layout, grouping, and scrolling

FunctionBehavior
same_line(offset?, spacing?)Keeps the next item on the current line.
dummy(width, height)Adds empty layout space.
indent(width?) / unindent(width?)Changes indentation.
begin_group_scope() / end_group_scope()Unframed item group.
begin_group_box(name, width?, height?) / end_group_box()Framed, named group box.
begin_group / end_groupBackward-compatible aliases for the group-box pair.
begin_disabled(disabled?) / end_disabled()Disables and visually dims a block.
columns(count?), next_column()Legacy column API; prefer tables for new UI.
set_column_width(index, width) / set_column_offset(index, offset)Legacy 1-based column settings.
column_width(index?)Legacy current/selected column width.
scroll_y() / scroll_max_y()Current vertical scroll and maximum.
set_scroll_y(y) / set_scroll_here_y(ratio?)Absolute or item-relative scrolling.
scroll_to_bottom()Convenience bottom scroll.

Cursor, IDs, widths, fonts, and focus

FunctionBehavior
cursor_pos() / set_cursor_pos(x, y)Window-local cursor.
cursor_pos_x(), cursor_pos_y()Individual local components.
set_cursor_pos_x(x), set_cursor_pos_y(y)Sets one component.
cursor_screen_pos()Screen-space cursor x, y.
content_available()Available width, height.
push_id(value) / pop_id()String or integer ID scope.
get_id(value)Current-stack hash for a string.
push_item_width(width) / pop_item_width()Scoped width.
set_next_item_width(width)One-shot width.
item_width()Resolved current item width.
set_keyboard_focus_here()Focuses the next submitted focusable item.
font_count()Number of loaded fonts.
push_font(index) / pop_font()1-based font scope.
font_size() / frame_height()Current metrics.
set_window_font_scale(scale)Scales the current window's font.
text_size(value)Returns measured width, height.

Item and input queries

Item queries describe the most recently submitted item:

text
item_hovered()
item_clicked(mouse_button?)
item_active()
item_focused()
item_visible()
item_rect_min()       -> x, y
item_rect_max()       -> x, y
item_rect_size()      -> width, height

Other input helpers:

text
key_pressed(key)
key_down(key)
mouse_clicked(button?)
mouse_double_clicked(button?)
mouse_down(button?)
mouse_released(button?)
mouse_pos()           -> x, y
mouse_delta()         -> dx, dy
mouse_wheel()
modifiers()           -> ctrl, shift, alt

mouse_button contains left, right, and middle. key provides common Win32-compatible key values including arrows, navigation keys, modifiers, Enter, Escape, Space, Delete, and F1 through F12.

Colors and styles

Packed colors are RGBA values used by widgets, style slots, and draw primitives:

text
color(r, g, b, a?)                 -- byte components, 0..255
color_float(r, g, b, a?)           -- float components, 0..1
color_hsv(h, saturation, value, a?)
color_r(color), color_g(color), color_b(color), color_a(color)
color_set_alpha(color, alpha_byte)

Style helpers:

text
push_style_color(index, color) / pop_style_color(count?)
push_style_var(index, value)
push_style_var_vec(index, x, y) / pop_style_var(count?)
get_style_color(index) / set_style_color(index, color)
get_style() / set_style(values)
style_dark() / style_light() / style_classic()

get_style() returns a Lua table containing editable scalar and {x, y} vector properties. set_style(values) applies the recognized keys present in a table, so it may receive either the complete snapshot or a partial update. Supported keys include alpha; window, child, popup, frame, scrollbar, grab, and tab geometry; padding and spacing vectors; indent spacing; and title-bar height.

style_color exposes all SharpGfx color slots: window, child and popup backgrounds; text; frame/button/header/tab states; check mark; slider and scrollbar states; separator; border; title; resize grip; and modal dim background.

style_var exposes alpha, window/child/popup/frame rounding and borders, padding and spacing vectors, indent spacing, scrollbar size/rounding, grab size/rounding, and tab rounding. Use push_style_var_vec for vector slots such as padding and spacing.

Drawing API

ui.draw writes to the current window draw list by default. The optional final layer is "window", "foreground"/"fg", or "background"/"bg". Coordinates are screen coordinates; use cursor_screen_pos() to anchor custom widgets.

text
line(x1, y1, x2, y2, color, thickness?, layer?)
rect(x1, y1, x2, y2, color, thickness?, rounding?, layer?)
rect_filled(x1, y1, x2, y2, color, rounding?, layer?)
rect_multicolor(x1, y1, x2, y2, top_left, top_right, bottom_right, bottom_left, layer?)
circle(x, y, radius, color, segments?, thickness?, layer?)
circle_filled(x, y, radius, color, segments?, layer?)
triangle(x1, y1, x2, y2, x3, y3, color, thickness?, layer?)
triangle_filled(x1, y1, x2, y2, x3, y3, color, layer?)
quad(x1, y1, x2, y2, x3, y3, x4, y4, color, thickness?, layer?)
quad_filled(x1, y1, x2, y2, x3, y3, x4, y4, color, layer?)
polyline(points, color, closed?, thickness?, layer?)
bezier_cubic(x1, y1, x2, y2, x3, y3, x4, y4, color, thickness?, segments?, layer?)
text(x, y, value, color, size?, layer?)
text_outlined(x, y, value, color, outline, size?, layer?)

polyline accepts either {{x1, y1}, {x2, y2}, ...} or {x1, y1, x2, y2, ...}. Invalid/nonfinite point data is rejected safely.

Clipping and channel helpers are draw.push_clip(x1, y1, x2, y2, layer?), draw.pop_clip(layer?), draw.channels_split(count, layer?), draw.channels_set(index, layer?), and draw.channels_merge(layer?). Channel indices are 1-based in Lua. Channel scopes are ignored while a table is active because tables reserve draw channels to keep row and cell backgrounds behind their contents.

Complete demo

Load scripts/ui_04_imgui_demo.lua as a module to get an interactive reference window. Its main menu opens console, log, overlay, property-editor, and secondary-window examples. The body exercises the new table, menu, scalar/vector input, multiline input, list-box, disabled-scope, progress, plot, tooltip, query, and draw-list APIs alongside the original SharpGfx widgets.

Arcane SDK catalog generated from scripts/sdk