Lifecycle and cleanup

Re-running your script, tearing a window down, and disconnecting everything cleanly.

Re-running replaces, it does not stack#

By default, running your script again closes the previous window and opens a fresh one:

Luau
local win = Ember.new({ Title = "My Script" })

That is deliberate. While you are working you run the same loadstring over and over, and without this every run leaves another live window behind — each with its own keybind, its own tile pool and its own dissolve. Pressing the toggle key then plays every one of them at once, which feels like the UI getting slower each time you execute.

To have two windows on screen together:

Luau
local win = Ember.new({ Title = "My Script", ReplaceExisting = false })

Only the newest window answers the keybind

Even with several windows open, the toggle key belongs to the most recently created one. Otherwise a single press would fire every window's animation simultaneously.

Destroying a window#

Luau
win:Destroy()

This disconnects every event Ember made, stops every running animation, clears its tile pool and removes the GUI. After it, the window is gone and nothing of it is still running.

Cleaning up your own work#

Your script has connections Ember knows nothing about. Register them and they are torn down with the window:

Luau
win:OnDestroy(function()
    heartbeat:Disconnect()
    myEspFolder:Destroy()
end)

You can register as many as you like; they run in order when the window is destroyed.

For a connection you want managed entirely by the window, Track takes it directly:

Luau
win:Track(game.Players.PlayerAdded:Connect(onPlayerAdded))

Tracked connections are disconnected on destroy without you writing any cleanup at all.

A complete, well-behaved script#

Luau
local Ember = loadstring(game:HttpGet('https://rbx.lol/ember.lua'))()
 
local win = Ember.new({ Title = "My Script", Subtitle = "v1.0" })
local main = win:Section("Main", "house")
 
local running = true
 
-- Managed by the window: gone when it is.
win:Track(game:GetService("RunService").Heartbeat:Connect(function()
    if not running then return end
    -- per-frame work
end))
 
main:Toggle({
    Text = "Enabled",
    Default = true,
    Callback = function(on) running = on end,
})
 
main:Button({
    Text = "Close",
    ButtonText = "Exit",
    Danger = true,
    Callback = function() win:Destroy() end,
})
 
win:OnDestroy(function()
    running = false
    print("cleaned up")
end)

What survives a destroy#

Saved settings. They are on disk, not in the window, so destroying a window and running the script again restores everything with a Save key — including the window's own size and position if you set SaveLayout = true.

To wipe them:

Luau
Ember.Store.clear("godmode")   -- one key

Checking whether a window is still alive#

Every window is registered while it exists:

Luau
local live = getgenv().__EMBER_LIVE   -- array of live windows
print(#live)

This is what ReplaceExisting reads to find the previous window. You rarely need it directly, but it is the honest answer to "is my old window still there".