Skip to content

User interface

Alexandre 'kidev' Poumaroux edited this page Oct 21, 2026 · 3 revisions

User interface

proleak.ui builds game UI from Python widgets, drawn with the game's own components. UI works on every server kind. Everything a plugin shows goes away when the plugin unloads, and an open page closes as if the player pressed Back.

Contents

Menus

from proleak import ui

ui.main_menu.add("Overlay", page="settings")
ui.game_menu.add("Say hi", on_click=lambda: ui.toast("hi"))

main_menu is the launcher list and game_menu the in-game menu. add(label, page=None, on_click=None, after=None, before=None, huge=False, badge=None) takes either a page name of the plugin or a callback, and returns an item with remove().

Without after or before the item goes at the end of the list, above the game's own last entries (Quit and Return to game in a match). after="<name>" and before="<name>" place it next to the game item with that name, or at the end when there is none.

Unit menu

from proleak import camera, ui

ui.unit_menu.add("First person", lambda unit: camera.pov(unit))
ui.unit_menu.add("Follow", lambda unit: camera.third_person(unit),
                 when=lambda unit: unit.owner is not None and unit.owner.is_local)

ui.unit_menu.add(label, on_click, when=None, alt=False) adds an entry to a menu that opens on a right-click on a unit. on_click(unit) gets the world Unit clicked, and when(unit) decides whether the entry shows for it. With alt=True the entry shows on Alt + right-click only. The call returns an item with remove().

When at least one entry shows, the menu replaces the game's ping wheel for that click. A right-click on the ground still opens the wheel.

Pages

mode = ui.state("fast")

@ui.page("settings", title="Overlay settings")
def build(p):
    p.add(
        ui.heading("Display"),
        ui.toggle("Show names", bind=ui.setting("enabled")),
        ui.slider("Size", 1, 5, bind=ui.setting("size")),
        ui.choice("Mode", ["fast", "full"], bind=mode),
        ui.button("Close", on_click=lambda: ui.close("settings")),
    )

A page opens in the game's own menu frame, with its title at the top left. Back returns to the menu it was opened from. The builder runs each time the page opens. ui.open(name) and ui.close(name) show and hide a page of the calling plugin, and ui.refresh(name) runs the builder again when the page is open. Registering a page name again replaces its builder. p.add(*widgets) appends widgets, p.tabs(*tabs) adds a tab bar, and p.redraw() runs the builder again.

Widget Arguments Callback
text(s)
heading(s)
button(label, on_click=None, style="standard", tone=None) style: standard, emphasized or text (menu buttons), small (for lists); a small button's tone is primary (gold, the main action), quiet (dimmed) or danger (red, removes something) on_click()
toggle(label, bind=None, on_change=None) an On/Off button like the game options on_change(value)
slider(label, min, max, step=1, bind=None, on_change=None) the game's slider; the value is sent on release on_change(value)
choice(label, options, bind=None, on_change=None) options: list of strings, in the game's drop-down on_change(value)
multi(label, options, bind=None, on_change=None) a drop-down where any number of options are ticked; the value is the ticked list, in option order on_change(value)
key(label, bind=None, on_change=None) a hotkey button: click it, then press a key (Escape cancels); the value is the Unity key name on_change(value)
color(label, bind=None, on_change=None) a #rrggbb color with a color picker on_change(value)
input(label, bind=None, on_change=None) reports on Enter or on losing focus on_change(value)
image(src) a path in the game's UI files, such as hud/img/icons/Gold.png
row(*widgets, align="start"), column(*widgets) side by side (align="end" against the right, align="split" with the last one against the right), stacked
group(*widgets) stacked in a framed box, one entry of a list
entry(title, *lines, buttons=(), badge=None, tone="neutral", author=None, version=None) a group with a heading, lines of text and small buttons, as the Mods menu lists plugins; buttons holds (label, on_click) pairs; badge is a short status beside the title, colored by tone (neutral, good, bad or busy)
table(headers, rows) lists of strings
tab(label, *widgets) one tab for p.tabs

ui.settings_form() returns the widgets for every setting the plugin declares (with settings.add or in plugin.yml), the same form the Mods menu shows, ready to add to a page. A plugin needs no page for its settings: the Mods menu gives every plugin with settings a Settings button.

bind connects an input widget to a value:

  • ui.state(value) holds a value in memory. Setting state.value redraws the widgets bound to it.
  • A Setting from settings.add, or ui.setting(key), binds to one of the plugin's settings; changes are validated and saved like settings.set.

A callback that raises counts against the plugin like a failing handler; the page keeps working.

Popups and toasts

ui.popup("Reset?", "Clear all names?", buttons=("Yes", "No"),
         on_result=lambda label: label == "Yes" and names.clear())
ui.toast("Names loaded", header="Overlay", seconds=4)

on_result receives the label of the clicked button. A toast appears with the launcher's notifications in the menus and in the game's message feed during a match.

Labels on units

ui.nameplate(unit, "alice", color="#33ff33")
ui.world_text(x, z, "rally here")

ui.nameplate(unit, text) shows a text label above a unit's health bar until the unit dies or is sold, and ui.world_text(x, z, text) places one at a map point. The User interface reference lists their options.

Panels and scripts

Panels and scripts reach the game's page directly. They can change anything on screen, including what the cosmetic rule protects, so the approved plugin list reviews them.

hud = ui.panel("score", '<button data-proleak-evt="reset">Reset</button>',
               css="button { color: gold; }", anchor="top-left")

@ui.on_js("reset")
def reset(data):
    ...

hud.send("score", 42)

ui.panel(name, html, css="", anchor="top-right") shows raw HTML in a corner: top-left, top-right, bottom-left, bottom-right or center. Clicking an element with data-proleak-evt calls the plugin's on_js handler for that event, with the element's data-value as data. panel.send(evt, data) delivers to the plugin's scripts and fires a proleak DOM event on the panel (event.detail holds evt and data).

ui.script(path) loads a .js file from the plugin folder into the game page. The script runs with one variable, api:

Member Use
api.send(evt, data) Call the plugin's on_js(evt) handler.
api.on(evt, fn) Receive panel.send(evt, data) from Python.
api.onUnload(fn) Clean up when the script or plugin unloads.
api.React, api.globalState The game's React and state.

Previous: Plugin settings | Next: Players, units and game data

Clone this wiki locally