Window API
Every option Ember.new accepts, and every method a window has.
Ember.new#
local win = Ember.new({ Title = "My Script" })Everything is optional.
Identity#
| Option | Type | Default | What it does |
|---|---|---|---|
Title | string | — | Shown in the title bar. |
Subtitle | string | — | A smaller second line under the title. |
Name | string | — | Name for the ScreenGui, and the identity ReplaceExisting matches on. Falls back to Title. |
Footer | string | "ember" | Small text at the bottom of the rail. |
Accent | Color3 | — | Sets the theme's accent. It is global: every live window repaints, the same as Ember.SetTheme({ accent = … }). |
Geometry#
| Option | Type | Default | What it does |
|---|---|---|---|
Size | Vector2 | Vector2.new(700, 452) | Starting size. |
MinSize | Vector2 | Vector2.new(560, 300) | The user cannot resize below this. |
MaxSize | Vector2 | — | Upper limit. Defaults to the viewport. |
Position | Vector2 | UDim2 | — | Where it opens. Centred if unset. |
Rail | number | 176 | Sidebar width in pixels. |
MinRail | number | 132 | Narrowest the sidebar can be dragged. |
MaxRail | number | 320 | Widest the sidebar can be dragged. |
MinContent | number | 300 | The content pane never shrinks past this. |
Resizable | boolean | true | Whether the resize grip is offered. |
SafeArea | boolean | true | Keeps the window inside the usable viewport. |
SaveLayout | boolean | string | false | Remember size, position and rail width between sessions. A string names the slot, so two windows can keep separate geometry; otherwise the slot is Name, then Title. |
Behaviour#
| Option | Type | Default | What it does |
|---|---|---|---|
Keybind | EnumItem | string | false | Enum.KeyCode.RightShift | The key that hides and shows the window. A string like "F4" works too. false means no toggle key. An unknown name warns and falls back to RightShift. |
ReplaceExisting | boolean | true | Close this script's previous window instead of stacking a second one. |
Search | boolean | false | Adds a search box to the rail that spans every section. |
SearchPlaceholder | string | — | Ghost text for that box. |
StatusBar | boolean | table | false | A strip along the bottom or top of the window. See Status bar below. |
Theme | string | — | Applies this theme as the window is built, so it wins over Config.Themes.Default and over an earlier SetTheme. |
ReapplyOnRespawn | boolean | false | Every control re-fires its callback when the character is replaced. A control can set Reapply = false to stay out. |
RevertOnClose | boolean | false | Every control is called with its off value when the window is destroyed. A control can set RevertOnClose = false to stay out, or RevertTo to pick the value it reverts to. |
ReapplyOnRespawn and RevertOnClose are covered in
Lifecycle and cleanup.
Status bar#
A strip along the bottom or top of the window, for things like what the script
is doing or an FPS readout. Minimise takes it away with the body and brings it
back.
local win = Ember.new({ Title = "Helper", StatusBar = true })
win.StatusBar:Set("Ready")It has three zones, left, center and right. Everything in it is an item
with an id, so a loop writing an FPS number and a one-off message do not tread
on each other.
local win = Ember.new({
Title = "Helper",
StatusBar = {
Position = "bottom",
Text = "Ready",
Icon = "circle-dot",
Items = {
{ Id = "fps", Align = "left", Text = "-- FPS", Icon = "gauge" },
{ Id = "ver", Align = "right", Text = "v2.4" },
},
},
})
game:GetService("RunService").RenderStepped:Connect(function(dt)
win.StatusBar:Item("fps", { Text = math.floor(1 / dt) .. " FPS" })
end)Options#
| Option | Type | Default | What it does |
|---|---|---|---|
Position | string | "bottom" | "bottom" or "top". Bottom sits on the window's edge; top sits under the title bar. |
Height | number | 24 | Clamped to 16–64. |
Text | string | — | The centre message. Shorthand for an item with the id "status". |
Icon | string | — | An icon for that message. |
Color | Color3 | string | "muted" | Its colour, as a Color3 or a theme role name. |
Items | array | — | Segments to build up front. Each takes Id, Align, Text, Icon, Color, Order and Visible. Order defaults to its position in the array. |
Methods#
| Method | Returns | What it does |
|---|---|---|
Set(text, opts?) | true / false, reason | Writes the centre message |
Get(id?) | string | nil | The text of an item, or of the centre message |
Item(id, opts) | true / false, reason | Creates or updates a segment |
Remove(id) | true / false, reason | Takes one out |
Items() | array | The ids currently in the bar, sorted |
Clear() | true | Empties it |
Show() / Hide() / SetVisible(v) | true | The body takes the space back when it is hidden |
IsVisible() | boolean | Whether it is showing |
Height() | number | Its height, or 0 while hidden |
Position() | string | "bottom" or "top" |
Item updates in place rather than rebuilding, so calling it every frame costs
a string assignment and not two instances. Item(id, "text") is shorthand for
Item(id, { Text = "text" }). Passing Icon = false removes an icon; leaving
Icon out keeps whatever is there. Item(id, false) is the same as
Remove(id).
Colours by role, not by hex
Color takes a theme role name such as "accent" or "muted", as well as a
Color3. A role name keeps the bar in step when the theme changes; a literal
colour does not.
Sections#
local main = win:Section("Main", "home")
-- with options
local big = win:Section("Everything", "list", {
Search = true,
SearchPlaceholder = "Filter this section…",
})The first section created is the one shown on open.
Methods#
Content#
| Method | What it does |
|---|---|
Section(name, icon, opts) | Adds a section and returns it |
Select(section) | Switches to a section |
Notify(opts) | Shows a notification |
ThemeEditor(opts?) | Builds a theme editor section and returns it |
Appearance#
| Method | What it does |
|---|---|
SetTitle(text) | Changes the title |
SetSubtitle(text) | Changes the subtitle |
SetSize(width, height) | Resizes |
SetMinSize(v) / SetMaxSize(v) | Changes the resize limits |
SetPosition(v) | Moves it |
SetRailWidth(n) | Resizes the sidebar |
Centre() / Center() | Centres it on screen. Both spellings work. |
State#
| Method | What it does |
|---|---|
Toggle(visible?) | Hides or shows, with the dissolve. Pass a boolean to force one way. |
Minimise(state?) / Minimize(state?) | Collapses to the title bar. Pass a boolean to force one way. |
SaveLayout() | Writes the current geometry to disk. false if the window was not created with SaveLayout. |
RestoreLayout() | Reads it back |
GetLayout() | Returns the current geometry as a table |
Lifecycle#
| Method | What it does |
|---|---|
Destroy(immediate?) | Tears the window down and disconnects everything. true skips the closing dissolve. |
OnDestroy(fn) | Registers cleanup to run on destroy |
OnRespawn(fn) | Runs fn(character) each time the character is replaced. Returns a subscription with :Disconnect(). |
Reapply() | Re-fires every opted-in control's callback now, without waiting for a respawn |
Track(connection) | Hands a connection to the window to disconnect for you |
A fully specified window#
local win = Ember.new({
Title = "Bloxburg Helper",
Subtitle = "v2.1",
Footer = "by you",
Size = Vector2.new(760, 500),
MinSize = Vector2.new(600, 340),
Rail = 190,
SaveLayout = true,
Keybind = Enum.KeyCode.RightControl,
Search = true,
StatusBar = { Text = "Ready", Icon = "circle-dot" },
})Pointer and cursor helpers#
Ember.Util holds the pointer tracking and cursor stack the window uses for its
own resize corner. Use them for anything draggable you build yourself.
| Function | Returns | What it does |
|---|---|---|
Util.pointerPosition(reference) | Vector2 | nil | The pointer in the same space as AbsolutePosition. Pass any instance inside the GUI you are measuring against. |
Util.pointerInside(instance, padding?) | boolean | nil | Whether the pointer is over that instance, with optional slack. nil means the position could not be read, which is not the same as false. |
Util.watchPointer(instance, fn, padding?) | subscription | Calls fn(inside) whenever that answer changes. :Disconnect() to stop. Returns nil if the instance or the function is missing. |
Util.setCursor(token, icon) | boolean | Requests a mouse cursor. Pass nil as the icon to drop the request. |
Util.Cursors | table | ResizeDiagonal, ResizeHorizontal, ResizeVertical, Hand |
local Util = Ember.Util
Util.watchPointer(myHandle, function(inside)
Util.setCursor(myHandle, inside and Util.Cursors.ResizeHorizontal or nil)
end, 3)watchPointer re-tests the rectangle every Heartbeat. MouseEnter and
MouseLeave do not fire when the object moves under a cursor that has not
itself moved, which is what happens during a drag. One shared connection drives
every watcher and it stops when the last one disconnects.
Cursor requests are a stack
setCursor shows the most recent request and falls back to the previous one
when that is dropped, then restores the game's own icon when none are left.
Drop your request when you are done, including on destroy, or the cursor stays
for the rest of the session.