Skip to main content
A plugin shows controls to the player in two places: its own page in the PLUGINS section of ReSkate’s menu (reskate.menu.page and reskate.menu.panel, which need the menu permission), and full-screen screens it opens itself (reskate.ui.screen, which needs ui.screen). Both are built from the same widgets. For short notices, see reskate.ui.toast. A plugin’s server copy shows neither.

The PLUGINS section

Each plugin with a page gets its own place in the menu, under its page’s title. In a window, the menu’s side rail has a PLUGINS group with one row per plugin. Full screen, a PLUGINS tab at the top has a tab per plugin. Both list the plugins by name. The section only shows while some plugin has a page. A plugin’s page is what reskate.menu.page builds, with the plugin’s panels (reskate.menu.panel) as cards under it. A plugin with panels and no page gets a page named after its id, holding just the panels.

How pages work

You give a page a function that builds it. ReSkate calls that function ten times a second while the menu shows your page, with a builder, ui, and your function calls ui’s widget functions in order, top to bottom. Nothing is kept from one build to the next: build the whole page each time, from your plugin’s own variables. While the menu shows another plugin’s page, or is closed, yours is not built at all. When the player uses a widget, what they did comes back in the next build: the widget’s function returns the new value instead of the one you passed. Keep it in your variable, and pass it the next time.

reskate.menu.page(title, build)

Gives your plugin its page in the PLUGINS section.
string
required
1 to 24 characters. It is the page’s name in the section, and a widget’s actions are matched to the page by it.
function
required
Called with ui each time the page is built.
Needs menu. A plugin has one page: a second call raises an error. So do an empty or too long title, a title one of your panels has, and a build that is not a function. A page holds at most 160 widgets in one build. Each build has 50 ms, like any handler.

reskate.menu.panel(title, build)

Adds a panel to your plugin’s page: a card titled with your title, under what the page builds. Panels are built with the page, only while the menu shows it.
string
required
1 to 40 characters, different from your plugin’s other panels and from its page’s title. A widget’s actions are matched to its panel by this title.
function
required
Called with ui each time the panel is built.
Needs menu. Raises an error for an empty or too long title, a title this plugin used already for a panel or its page, a build that is not a function, and more than 8 panels. A panel holds at most 64 widgets.

Layout

Every widget function is called on ui with a colon, only inside a page’s, a panel’s or a screen’s build function: called anywhere else, it raises an error.

ui:card(title, subtitle)

A titled tile, the kind the menu’s own pages are built from. The widgets after it go in it, until the next card or the end of the build. Widgets before the first card sit on the page itself. A panel is a card already; a card inside it starts a new one.
string
required
At most 60 characters.
string
A line under the title, at most 120 characters.

ui:tabs(id, names, chosen)

A row of tabs on the page. Build the chosen tab’s widgets after it: a page builds only the tab shown, so its 160 widgets are counted for that tab alone.
string
required
1 to 32 characters, as other widgets’ ids.
table
required
A list of 1 to 8 names, each at most 24 characters.
integer
default:"1"
The number of the tab shown, from 1.
integer
The tab the player picked, when they picked one since the last build; otherwise chosen. Always 1 to the number of names.

ui:heading(text)

A section heading inside a card.
string
required
At most 300 characters.

ui:label(text)

A line of text, wrapped to the card’s width.
string
required
At most 300 characters.

ui:note(text)

Muted help text, for what the setting above it does.
string
required
At most 300 characters.

ui:warn(text)

A warning, for something the player has to fix or know.
string
required
At most 300 characters.

ui:info(label, value)

A status line: a muted label, and its value beside it.
string
required
At most 60 characters.
string
required
At most 200 characters.

ui:separator()

A horizontal line between widgets.

Controls

Widgets the player can use (tabs, button, toggle, slider, dropdown) take an id: 1 to 32 characters, different from the other widgets’ ids in the same build of the page or panel. The id is how the player’s action finds its widget, so keep it the same from one build to the next.

ui:button(id, text, primary)

A button.
string
required
1 to 32 characters.
string
required
Its label, at most 60 characters.
boolean
default:"false"
True draws it as the card’s main action.
boolean
true in the build after the player pressed it, otherwise false.

ui:toggle(id, text, on, help)

A switch, on or off.
string
required
1 to 32 characters.
string
required
Its label, at most 60 characters.
boolean
default:"false"
Whether it shows on.
string
What it does, at most 300 characters, shown with it.
boolean
What the player set it to, when they changed it since the last build; otherwise on.

ui:slider(id, text, value, minimum, maximum, format)

A slider between two numbers.
string
required
1 to 32 characters.
string
required
Its label, at most 60 characters.
number
required
Its value now.
number
required
The left end.
number
required
The right end, above minimum.
string
default:"\"%.2f\""
How the value shows on the slider, at most 24 characters: exactly one %f (or %.Nf, N a single digit) or %d, among plain text, with %% for a percent sign. For example "%d%%", "%.1f m" or "x%.2f". Anything else raises an error.
number
What the player set, when they moved it since the last build; otherwise value. Always between minimum and maximum.
%d shows the value rounded, but the value that comes back is not: round it yourself, as above, when you want whole numbers.

ui:dropdown(id, text, choices, chosen, help)

A list to pick one from.
string
required
1 to 32 characters.
string
required
Its label, at most 60 characters.
table
required
A list of 1 to 32 strings, each at most 60 characters.
integer
default:"1"
The number of the choice shown, from 1.
string
What it does, at most 300 characters, shown with it.
integer
The number of the choice the player picked, when they picked one since the last build; otherwise chosen. Always 1 to the number of choices.

ui:bar(text, value, minimum, maximum)

A gauge the player cannot change: a progress bar with a label on it.
string
required
Its label, at most 60 characters.
number
required
Where it is, kept between minimum and maximum.
number
required
Empty.
number
required
Full, above minimum.
A widget raises an error outside a build function, past 160 widgets in a page’s build or 64 in a panel’s, for an id that is empty, longer than 32 characters or used twice in the build, for text over its length, for a maximum that is not above minimum, for a number that is not finite (or is beyond a million either way), for a dropdown with no choices or more than 32, for tabs with no names or more than 8, and for a slider format that is not exactly one number.

A whole page

The grind-exits plugin (contrib/plugins/grind-exits/plugin/main.lua in the ReSkate repository) builds its page from cards, help text, a slider format, a warning and status lines. Shortened:
The fpv-drone plugin (contrib/plugins/fpv-drone/plugin/page.lua) puts five tabs on its page, each with cards of its own.

Full-screen screens

A screen covers the whole game window, over everything, with your title at the top and the input while it shows. The player closes it with Esc. Use one for a mode’s lobby, a results table, or anything the player should look at before playing on.

reskate.ui.screen(title, build)

Adds a screen. It is built ten times a second while it is open, whether or not a menu is.
string
required
1 to 40 characters, different from your plugin’s other screens. It is shown at the top, with your plugin’s id and “Esc closes it” under it.
function
required
Called with ui each time the screen is built. It takes the same widgets as a page, drawn plainly: a card is a heading with its subtitle under it, and tabs are a row of names to pick from.
Needs ui.screen. Raises an error for a title that is empty or longer than 40 characters, a title this plugin used already, a build that is not a function, and more than 4 screens.

reskate.ui.open(title)

Opens one of your screens. A plugin has one screen open at a time: opening another replaces it.
string
required
A screen’s title.
Needs ui.screen. Raises an error for a title you added no screen for.

reskate.ui.close()

Closes your open screen, if one is open. Closing it this way does not fire screen_closed.
Needs ui.screen.

The screen_closed event

Fires when the player closes your screen with Esc, with the screen’s title. It needs ui.screen. See events.
While your screen is open, it has the player’s input: the game behind it does not get the keys. Close it when you are done with it, and let Esc close it.