rb.overlay draws toasts, menus, text prompts, status strips, progress bars and
surfaces you lay out yourself. A script reaches for it to show its state, or to
ask for a choice or a line of text, without taking focus from the app in front.
They show over every app on Windows and macOS, including full-screen ones,
except a Windows game in exclusive full-screen mode (see
Overlay limits). Overlays never take focus or clicks, so the
app underneath keeps working. Every call returns at once; Rebind draws the
latest state.
Needs: min_sdk=3.11.1.
This script counts F7 presses on a strip at the top of the screen and toasts the
count on F8:
Widget handles take a dot (
status.set(text)); a surface takes a colon
(surface:set(fields)). The other form fails or draws the wrong text.
A script’s overlays are removed when it stops, errors or reloads, and hidden
while it is inactive because focus left its target window.
Themes and text
Every widget takestheme: "rebind" (the default), "rebind-light",
"catppuccin", "tokyo-night" or "contrast", or a table with the same
roles. Text is the bundled JetBrains Mono, so columns line up. Text is a string
(a newline starts a line) or a list of spans, each a string or
{ text, color, bold }. A color is "#rrggbb", "#rrggbbaa" or a theme role:
"text", "dim", "faint", "accent", "positive", "warning" or
"danger".
This script shows a toast at start in the tokyo-night theme, with its first
span bold in the warning role:
Placement
Widgets and surfaces take ananchor: "top-left", "top", "top-right",
"left", "center", "right", "bottom-left", "bottom" or
"bottom-right", inside the work area of a display: "active" (default, the
monitor holding the foreground window), "primary" or "mouse". offset_x
and offset_y move it inward. An anchored overlay follows the foreground
window to another monitor within half a second. Alternatively, x and y
place the top-left corner in rb.screen coordinates. Sizes are logical units,
scaled for each monitor.
rb.overlay.toast
Shows forduration milliseconds (default 4000). Options: title and meta
add a heading line; max_width caps the width (default 640). Toasts at the
same anchor stack. A toast asked for while visible() is false waits until
overlays show, or gives up after expires milliseconds (default 60000).
rb.overlay.menu
While open, the menu takes Up, Down, Enter, Escape and 1 to 9, and swallows them so the app underneath does not see them. Enter or a number picks a row: the menu closes first unlesskeep_open is set, then the item’s
action(index, item) runs, then on_select(index, item). Escape closes it,
and so does the script losing focus to a window it does not target or the OS
hiding overlays (checked every 500 ms). on_close runs when the menu closes in
any of those ways or by close(); rb.overlay.clear() and the script stopping
close it without on_close. Items are strings or
{ label, hint, action }; hint shows on the right. Options: title,
subtitle, width. The handle’s select(index) moves the highlight and
close() closes it.
One menu or prompt across all scripts holds the keyboard at a time.
rb.overlay.menu returns nil, "a menu is already open" while this script has
one open, nil, "another menu is open" while another script’s menu or prompt is
open or while this script is unfocused, and
nil, "overlays are hidden" while visible() is false. A bind the script
made earlier on one of the menu’s keys, and that swallows it, takes the key
before the menu does.
This script opens a two-row menu on F8; picking Start farming logs start:
rb.overlay.prompt
Needs:min_sdk=3.15.0.
rb.overlay.prompt shows a one-line text field, for the kind of answer a
file-name dialog or a typed setting would ask for.
It types through swallowing binds, as the menu does, so it takes no focus and the app
underneath keeps its mouse and every key the prompt does not take.
While open, the prompt takes every letter, digit and punctuation key, the
numpad keys that type a character (digits, /, *, -, + and ., whatever
the Num Lock state), Space, Backspace, Enter, numpad Enter and Escape, and
swallows them. Each
key types its US-layout character, and Shift picks the shifted one. Ctrl+V
pastes the clipboard (Cmd+V as well on macOS): control characters become
spaces, the text stops at max_length, and an empty clipboard does nothing.
In a script that declares permissions, pasting needs the
clipboard:read
permission; without
it the chord does nothing. Ctrl, Alt and Win chords on any other key reach the
app.
Enter closes the prompt, then runs on_submit(text). Escape, close(), the
script losing focus to a window it does not target, and the OS hiding overlays
close it and run on_cancel(). on_close() then runs after either.
rb.overlay.clear() and the script stopping close it without running any of
them. Options: title, value (the starting text), placeholder (shown while
the field is empty), max_length (characters, 1 to 256, default 128), width
(default 360, or wider to fit the label and title). The handle’s text holds what was typed, and set(text)
replaces it; value and set turn control characters into spaces and cut the
text at max_length, as paste does. When the text is wider than the field, the field shows its end.
A prompt counts as a menu for the reasons above: it returns nil, "a menu is already open", nil, "another menu is open" or nil, "overlays are hidden"
under the same conditions, and a menu cannot open while a prompt is open. An error
raised inside on_submit lets the Enter press through to the app, as for a
menu pick.
Limits:
- Key names are physical keys, so a layout other than US types the US character for each key. Paste is the way to enter other layouts and Unicode.
- Caps Lock is not read. There is no input method editor and no mouse caret; typing and Backspace act at the end of the text.
- Rebind does not dispatch key repeat to binds, so holding a key types or deletes once.
- A bind the script made earlier on one of these keys, or a bind or blocking
handler in a script with a higher
z_index, takes the key before the prompt does.
rb.overlay.surface
Draws a list of ops you lay out yourself, in logical units from the surface’s top-left corner.width and height are required (1 to 4096, and at most
1,000,000 square units together); opacity is 0 to 1; capturable is
described under Overlay limits. Ops:
{ kind = "rect", x, y, w, h, fill, border, border_width, radius, shadow };shadowdraws a soft shadow 8 units below, blurred over 24:trueis 50% black, or give its opacity from 0 to 1. Each theme’sshadowholds the opacity its widgets use.{ kind = "text", x, y, size, text, color, bold }or{ kind = "text", x, y, size, spans };yis the top of the line,size6 to 96 (default 14).{ kind = "image", x, y, w, h, png };pngis the bytes of a PNG file, for examplerb.file.read_bytes("icon.png").wandhdefault to the image’s size in pixels. A PNG that fails to decode draws nothing. An image op needsmin_sdk=3.14.0.
set(fields) merges fields into the surface and redraws; draw(ops) replaces
the ops. A script may have 16 surfaces at once, covering at most 2,000,000
square units together, with 256 ops, 4,096 bytes of text, 1,048,576 bytes of
PNG and 4,194,304 image pixels (2048 by 2048) in each. Invalid
options raise a message starting rb.overlay:. A toast that waited for hidden
overlays and then cannot show is dropped with a warning in the script’s log.
Overlay limits
- A game in exclusive full-screen mode on Windows hides overlays;
visible()returnsfalsethen. Borderless and windowed games show them. On macOSvisible()turnsfalseonly after the overlays on screen have been covered for 2 seconds; with none on screen it returnstrue. - Overlays stay out of screenshots and recordings on Windows, and out of
screenshots on macOS; macOS screen recordings may include them. A widget or
surface given
capturable = trueshows in screenshots and recordings on both;capturableneedsmin_sdk=3.14.0. - Screen reads under an overlay that is not capturable return what is beneath it. On macOS, every script’s reads under a capturable one include its pixels, and a read under any overlay takes 10 to 25 ms, so a script should not draw over a region it reads every tick.