Full showcase

One script that turns on every control Ember has, wired to something real.

Every control below does something in-game. It is the fastest way to see what the library looks like when it is actually driving a script rather than demonstrating itself.

Press RightShift to hide and show the window. P is panic — it turns everything off at once.

It writes to disk

Toggles, sliders and the theme are saved, so the window comes back the way you left it. Everything lands in one file; the Advanced group in Settings has a button to clear it.

What it looks like#

Working, in every theme, before you run anything. Switch sections in the sidebar and use the controls — they are the same components the control pages document.

Live — click anything

Ember

live showcase

Enabled

FireOnStart runs the callback once at build time.

Speed

16 studs/s

Panic key

Outlined

The house style, and the default.

Save configuration

Delete config

Mode

ESP colour

Trail colour

Enabled

FireOnStart runs the callback once at build time.

Rooms

Status

idle

Icon strip

Each entry carries its own behaviour.

Filter

Debug logging
Verbose output

Enabled

FireOnStart runs the callback once at build time.

Developer mode

Unlocks the action below.

Start the farm

Runs until you stop it.

Outlined

The house style, and the default.

Filled

Ghost

Soft

Danger

60 FPSReadyEmber 3.0.0

Switch sections in the sidebar, drag the sliders, open the menus, pick a colour. The swatches above change the theme, the same way Ember.SetTheme does in-game.

The script#

Luau
--!nocheck
--!nolint UnknownGlobal
-- Ember showcase. RightShift hides the window, P turns everything off.
 
local Ember = loadstring(game:HttpGet("https://rbx.lol/ember.lua"))()
 
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local Lighting = game:GetService("Lighting")
 
local player = Players.LocalPlayer
 
local S = {
    flySpeed = 80,
    espMode = "Both",
    espColour = Color3.fromRGB(90, 209, 122),
    trailColour = Color3.fromRGB(74, 168, 240),
}
 
local lightBackup = {
    Brightness = Lighting.Brightness,
    Ambient = Lighting.Ambient,
    OutdoorAmbient = Lighting.OutdoorAmbient,
    FogEnd = Lighting.FogEnd,
    GlobalShadows = Lighting.GlobalShadows,
}
 
local function characterOf(who) return who and who.Character end
local function humanoidOf(c) return c and c:FindFirstChildOfClass("Humanoid") end
local function rootOf(c)
    return c and (c:FindFirstChild("HumanoidRootPart")
        or c:FindFirstChild("UpperTorso") or c:FindFirstChild("Torso"))
end
local function destroy(x)
    if x then pcall(function() x:Destroy() end) end
end
 
--=============================================================================
-- FEATURES
--=============================================================================
 
local function setWalkSpeed(v)
    local h = humanoidOf(characterOf(player))
    if h then h.WalkSpeed = v end
end
 
local function setJumpPower(v)
    local h = humanoidOf(characterOf(player))
    if not h then return end
    pcall(function() h.JumpPower = v end)
    pcall(function() h.JumpHeight = math.clamp(v / 7.2, 0, 50) end)
end
 
------------------------------------------------------------------- fly ------
local flyConn, flyAtt, flyVel, flyOri, flyHum, flyStand
 
local function stopFly()
    if flyConn then flyConn:Disconnect() end
    destroy(flyVel); destroy(flyOri); destroy(flyAtt)
    flyConn, flyVel, flyOri, flyAtt = nil, nil, nil, nil
    if flyHum then
        local h, previous = flyHum, flyStand
        pcall(function() h.PlatformStand = previous end)
    end
    flyHum, flyStand = nil, nil
end
 
local function startFly()
    stopFly()
    local character = characterOf(player)
    local root = rootOf(character)
    local humanoid = humanoidOf(character)
    if not root or not humanoid then return false end
 
    flyHum, flyStand = humanoid, humanoid.PlatformStand
    humanoid.PlatformStand = true
 
    flyAtt = Instance.new("Attachment")
    flyAtt.Name = "EmberFly"
    flyAtt.Parent = root
 
    flyVel = Instance.new("LinearVelocity")
    flyVel.Attachment0 = flyAtt
    flyVel.RelativeTo = Enum.ActuatorRelativeTo.World
    flyVel.VelocityConstraintMode = Enum.VelocityConstraintMode.Vector
    flyVel.MaxForce = math.huge
    flyVel.VectorVelocity = Vector3.zero
    flyVel.Parent = root
 
    flyOri = Instance.new("AlignOrientation")
    flyOri.Attachment0 = flyAtt
    flyOri.Mode = Enum.OrientationAlignmentMode.OneAttachment
    flyOri.RigidityEnabled = true
    flyOri.CFrame = root.CFrame.Rotation
    flyOri.Parent = root
 
    flyConn = RunService.PreSimulation:Connect(function()
        local camera = workspace.CurrentCamera
        if not camera or not flyVel or not flyVel.Parent then return end
        local direction = Vector3.zero
        if UserInputService:IsKeyDown(Enum.KeyCode.W) then direction += camera.CFrame.LookVector end
        if UserInputService:IsKeyDown(Enum.KeyCode.S) then direction -= camera.CFrame.LookVector end
        if UserInputService:IsKeyDown(Enum.KeyCode.A) then direction -= camera.CFrame.RightVector end
        if UserInputService:IsKeyDown(Enum.KeyCode.D) then direction += camera.CFrame.RightVector end
        if UserInputService:IsKeyDown(Enum.KeyCode.Space) then direction += Vector3.yAxis end
        if UserInputService:IsKeyDown(Enum.KeyCode.LeftControl) then direction -= Vector3.yAxis end
        flyVel.VectorVelocity = (direction.Magnitude > 0 and direction.Unit or Vector3.zero) * S.flySpeed
        flyOri.CFrame = camera.CFrame.Rotation
    end)
    return true
end
 
------------------------------------------------------- infinite jump --------
local jumpConn
 
local function stopInfiniteJump()
    if jumpConn then jumpConn:Disconnect() end
    jumpConn = nil
end
 
local function startInfiniteJump()
    stopInfiniteJump()
    jumpConn = UserInputService.JumpRequest:Connect(function()
        local h = humanoidOf(characterOf(player))
        if h then h:ChangeState(Enum.HumanoidStateType.Jumping) end
    end)
end
 
---------------------------------------------------------------- noclip ------
local noclipConn
 
local function stripCollision()
    local character = characterOf(player)
    if not character then return end
    for _, part in ipairs(character:GetDescendants()) do
        if part:IsA("BasePart") then part.CanCollide = false end
    end
end
 
local function stopNoclip()
    if noclipConn then noclipConn:Disconnect() end
    noclipConn = nil
    local root = rootOf(characterOf(player))
    if root then root.CanCollide = true end
end
 
local function startNoclip()
    stopNoclip()
    stripCollision()
    -- The Humanoid puts CanCollide back every physics step, so this has to run
    -- every step rather than once.
    noclipConn = RunService.PreSimulation:Connect(stripCollision)
end
 
------------------------------------------------------------------- esp ------
local espOn, espMap = false, {}
 
local function paintHighlight(hl)
    local fill = S.espMode == "Fill" or S.espMode == "Both"
    local outline = S.espMode == "Outline" or S.espMode == "Both"
    hl.FillColor = S.espColour
    hl.OutlineColor = S.espColour
    hl.FillTransparency = fill and 0.55 or 1
    hl.OutlineTransparency = outline and 0 or 1
    hl.DepthMode = Enum.HighlightDepthMode.AlwaysOnTop
end
 
local function clearESP()
    espOn = false
    for _, hl in pairs(espMap) do destroy(hl) end
    table.clear(espMap)
end
 
local function refreshESP()
    if not espOn or S.espMode == "Off" then
        for who, hl in pairs(espMap) do
            destroy(hl)
            espMap[who] = nil
        end
        return
    end
    for _, who in ipairs(Players:GetPlayers()) do
        local character = who ~= player and who.Character or nil
        if character then
            local hl = espMap[who]
            if not hl or not hl.Parent or hl.Adornee ~= character then
                destroy(hl)
                hl = Instance.new("Highlight")
                hl.Name = "EmberESP"
                hl.Adornee = character
                hl.Parent = character
                espMap[who] = hl
            end
            paintHighlight(hl)
        end
    end
    for who, hl in pairs(espMap) do
        if not who.Parent then
            destroy(hl)
            espMap[who] = nil
        end
    end
end
 
local function startESP()
    espOn = true
    refreshESP()
end
 
--------------------------------------------------------------- rainbow ------
local rainbowConn
 
local function stopRainbow()
    if rainbowConn then rainbowConn:Disconnect() end
    rainbowConn = nil
end
 
local function startRainbow()
    stopRainbow()
    local started = os.clock()
    rainbowConn = RunService.RenderStepped:Connect(function()
        S.espColour = Color3.fromHSV((os.clock() - started) * 0.25 % 1, 0.85, 1)
        for _, hl in pairs(espMap) do
            if hl.Parent then paintHighlight(hl) end
        end
    end)
end
 
----------------------------------------------------------------- trail ------
local trail, trailTop, trailBottom
 
local function stopTrail()
    destroy(trail); destroy(trailTop); destroy(trailBottom)
    trail, trailTop, trailBottom = nil, nil, nil
end
 
local function startTrail()
    stopTrail()
    local root = rootOf(characterOf(player))
    if not root then return end
 
    trailTop = Instance.new("Attachment")
    trailTop.Position = Vector3.new(0, 0.6, 0)
    trailTop.Parent = root
 
    trailBottom = Instance.new("Attachment")
    trailBottom.Position = Vector3.new(0, -0.6, 0)
    trailBottom.Parent = root
 
    trail = Instance.new("Trail")
    trail.Attachment0 = trailTop
    trail.Attachment1 = trailBottom
    trail.Color = ColorSequence.new(S.trailColour)
    trail.Transparency = NumberSequence.new({
        NumberSequenceKeypoint.new(0, 0.12),
        NumberSequenceKeypoint.new(1, 1),
    })
    trail.Lifetime = 0.9
    trail.MinLength = 0.08
    trail.LightEmission = 0.85
    trail.FaceCamera = true
    trail.Parent = root
end
 
------------------------------------------------------ world settings --------
local function setFullbright(on)
    if on then
        Lighting.Brightness = 2
        Lighting.Ambient = Color3.new(1, 1, 1)
        Lighting.OutdoorAmbient = Color3.new(1, 1, 1)
        Lighting.FogEnd = 1e6
        Lighting.GlobalShadows = false
    else
        for property, value in pairs(lightBackup) do
            pcall(function() Lighting[property] = value end)
        end
    end
end
 
local function setFov(v)
    local camera = workspace.CurrentCamera
    if camera then camera.FieldOfView = v end
end
 
--=============================================================================
-- WINDOW
--=============================================================================
 
local win = Ember.new({
    Title = "Ember",
    Subtitle = "live showcase",
    Icon = "flame",
    Footer = "everything here is real",
    Size = Vector2.new(820, 560),
    Keybind = Enum.KeyCode.RightShift,
    Search = true,
    SaveLayout = true,
    ReapplyOnRespawn = true,
    RevertOnClose = true,
    StatusBar = {
        Text = "Ready",
        Icon = "circle-dot",
        Items = {
            { Id = "fps", Align = "left", Text = "-- FPS", Icon = "gauge" },
            { Id = "ver", Align = "right", Text = "Ember " .. tostring(Ember.Version or "") },
        },
    },
})
 
local function say(text, icon, colour)
    win.StatusBar:Set(text, { Icon = icon or "circle-dot", Color = colour or "muted" })
end
 
local fpsTime, fpsFrames = 0, 0
win:Track(RunService.RenderStepped:Connect(function(dt)
    fpsTime += dt
    fpsFrames += 1
    if fpsTime < 0.25 then return end
    win.StatusBar:Item("fps", { Text = math.floor(fpsFrames / fpsTime + 0.5) .. " FPS" })
    fpsTime, fpsFrames = 0, 0
end))
 
-- Panic drives the controls rather than the features, so the switches end up
-- agreeing with what is actually off. Registered here so nothing can be
-- forgotten from a hand-written list later.
local resettable = {}
local function resets(handle, offValue)
    table.insert(resettable, { handle = handle, off = offValue })
    return handle
end
 
local function panic()
    for _, entry in ipairs(resettable) do
        pcall(function() entry.handle:Set(entry.off) end)
    end
    say("Everything off", "shield", "danger")
    win:Notify({
        Title = "Panic",
        Text = "Every feature disabled.",
        Icon = "shield",
        IconColor = Ember.Theme.danger,
    })
end
 
--=============================================================================
-- MOVEMENT
--=============================================================================
 
local move = win:Section("Movement", "compass")
move:Title({ Text = "PHYSICS", Icon = "zap" })
 
resets(move:Toggle({
    Text = "Fly",
    Description = "WASD to move, Space up, Left Ctrl down. Camera-relative.",
    Save = "fly",
    Reapply = true,
    OnEnabled = function()
        if startFly() then
            say("Flying", "feather", "accent")
        else
            say("No character to fly", "triangle-alert", "danger")
        end
    end,
    OnDisabled = function()
        stopFly()
        say("Ready")
    end,
}), false)
 
resets(move:Slider({
    Text = "Fly speed",
    Min = 10, Max = 250, Default = 80, Step = 5, Suffix = " studs/s",
    Save = "flySpeed",
    Callback = function(v) S.flySpeed = v end,
}), 80)
 
resets(move:Slider({
    Text = "Walk speed",
    Min = 8, Max = 250, Default = 16, Step = 1, Suffix = " studs/s",
    Save = "walkSpeed",
    Reapply = true,
    Callback = setWalkSpeed,
}), 16)
 
resets(move:Slider({
    Text = "Jump power",
    Min = 0, Max = 250, Default = 50, Step = 1,
    Save = "jumpPower",
    Reapply = true,
    Callback = setJumpPower,
}), 50)
 
move:Title({ Text = "UTILITIES", Icon = "wrench" })
 
resets(move:Toggle({
    Text = "Infinite jump",
    Description = "Jump mid-air as many times as you want.",
    Save = "infiniteJump",
    OnEnabled = startInfiniteJump,
    OnDisabled = stopInfiniteJump,
}), false)
 
resets(move:Toggle({
    Text = "Noclip",
    Description = "Walk through walls.",
    Save = "noclip",
    Reapply = true,
    OnEnabled = startNoclip,
    OnDisabled = stopNoclip,
}), false)
 
move:Keybind({
    Text = "Panic key",
    Description = "Turns every feature off at once.",
    Default = Enum.KeyCode.P,
    Save = "panicKey",
    Callback = panic,
})
 
move:Separator()
move:Title({ Text = "STATE", Icon = "lock" })
move:Description("Disabled, DisabledReason and Tooltip work on every control.")
 
local gated
move:Toggle({
    Text = "Unlock the button below",
    Tooltip = "Hover anything with a Tooltip to see this",
    OnEnabled = function() if gated then gated:Enable() end end,
    OnDisabled = function()
        if gated then gated:Disable("Turn on the switch above first") end
    end,
})
 
gated = move:Button({
    Text = "Gated action",
    Description = "Refuses the click until it is enabled.",
    ButtonText = "Go",
    Style = "filled",
    Disabled = true,
    DisabledReason = "Turn on the switch above first",
    Callback = function() say("Gated action ran", "check", "accent") end,
})
 
move:Slider({
    Text = "Hover me",
    Min = 0, Max = 100, Default = 40,
    Tooltip = "The tooltip follows your cursor and fades in",
})
 
move:Button({
    Text = "Reset character",
    ButtonText = "Reset",
    ButtonIcon = "rotate-cw",
    Danger = true,
    Click = { Rotate = 360 },
    Callback = function()
        local h = humanoidOf(characterOf(player))
        if h then h.Health = 0 end
    end,
})
 
--=============================================================================
-- VISUALS
--=============================================================================
 
local vis = win:Section("Visuals", "eye")
vis:Title({ Text = "PLAYER ESP", Icon = "scan" })
 
resets(vis:Toggle({
    Text = "ESP",
    Description = "A highlight on every other player.",
    Default = true,
    Save = "esp",
    Reapply = false,
    OnEnabled = function()
        startESP()
        say("ESP on", "eye", "accent")
    end,
    OnDisabled = function()
        clearESP()
        say("Ready")
    end,
}), false)
 
vis:Dropdown({
    Text = "ESP mode",
    Options = { "Off", "Outline", "Fill", "Both" },
    Default = "Both",
    Save = "espMode",
    Reapply = false,
    Callback = function(mode)
        S.espMode = mode
        refreshESP()
    end,
})
 
vis:ColorPicker({
    Text = "ESP colour",
    Description = "Full HSV wheel, shade square, hue strip, hex.",
    Default = S.espColour,
    Save = "espColour",
    Reapply = false,
    Callback = function(c)
        S.espColour = c
        refreshESP()
    end,
})
 
resets(vis:Toggle({
    Text = "Rainbow ESP",
    Description = "Cycles the highlight hue. Overrides the colour above.",
    Save = "rainbow",
    Reapply = false,
    OnEnabled = startRainbow,
    OnDisabled = function()
        stopRainbow()
        refreshESP()
    end,
}), false)
 
vis:Title({ Text = "TRAIL AND WORLD", Icon = "wind" })
 
resets(vis:Toggle({
    Text = "Motion trail",
    Description = "A glowing ribbon behind you.",
    Default = true,
    Save = "trail",
    Reapply = true,
    OnEnabled = startTrail,
    OnDisabled = stopTrail,
}), false)
 
vis:Palette({
    Text = "Trail colour",
    Default = S.trailColour,
    Save = "trailColour",
    Reapply = false,
    Callback = function(colour)
        S.trailColour = colour
        if trail then trail.Color = ColorSequence.new(colour) end
    end,
})
 
resets(vis:Toggle({
    Text = "Fullbright",
    Description = "Removes shadows and fog.",
    Save = "fullbright",
    Reapply = false,
    OnEnabled = function() setFullbright(true) end,
    OnDisabled = function() setFullbright(false) end,
}), false)
 
resets(vis:Slider({
    Text = "Field of view",
    Min = 40, Max = 120, Default = 70, Step = 1,
    Save = "fov",
    Reapply = false,
    Callback = setFov,
}), 70)
 
--=============================================================================
-- PLAYERS
--=============================================================================
 
local plrSec = win:Section("Players", "users")
plrSec:Title({ Text = "SERVER", Icon = "globe" })
 
local function otherNames()
    local names = {}
    for _, who in ipairs(Players:GetPlayers()) do
        if who ~= player then table.insert(names, who.Name) end
    end
    table.sort(names)
    if #names == 0 then table.insert(names, "(nobody else)") end
    return names
end
 
local target = plrSec:Dropdown({
    Text = "Target",
    Options = otherNames(),
    Default = otherNames()[1],
    Reapply = false,
})
 
local playerCount = plrSec:Status({
    Text = "Players online",
    Default = tostring(#Players:GetPlayers()),
})
 
local function refreshPlayers()
    local names = otherNames()
    target:SetOptions(names, true)
    target:Set(names[1], true)
    playerCount:Set(tostring(#Players:GetPlayers()))
    refreshESP()
end
 
win:Track(Players.PlayerAdded:Connect(function(who)
    who.CharacterAdded:Connect(function() task.defer(refreshESP) end)
    refreshPlayers()
end))
win:Track(Players.PlayerRemoving:Connect(function(who)
    destroy(espMap[who])
    espMap[who] = nil
    refreshPlayers()
end))
for _, who in ipairs(Players:GetPlayers()) do
    win:Track(who.CharacterAdded:Connect(function() task.defer(refreshESP) end))
end
 
plrSec:Button({
    Text = "Teleport to target",
    ButtonText = "TP",
    ButtonIcon = "crosshair",
    Style = "filled",
    Click = { Icon = "check", Text = "Gone", Hold = 1 },
    Callback = function()
        local name = target:Get()
        local who = Players:FindFirstChild(name)
        local from = rootOf(characterOf(player))
        local to = who and rootOf(characterOf(who))
        if not from or not to then
            say("Target has no character", "triangle-alert", "danger")
            return
        end
        from.CFrame = to.CFrame * CFrame.new(0, 0, 3)
        say("Teleported to " .. name, "crosshair", "accent")
    end,
})
 
plrSec:IconButton({
    Text = "Quick actions",
    Description = "Refresh the list, repaint ESP, panic.",
    Buttons = {
        { Icon = "refresh-cw", Click = { Rotate = 360 }, Callback = refreshPlayers },
        { Icon = "eye", Callback = refreshESP },
        { Icon = "shield", Danger = true, Callback = panic },
    },
})
 
--=============================================================================
-- SETTINGS
--=============================================================================
 
local settings = win:Section("Settings", "settings")
settings:Title({ Text = "THEME", Icon = "brush" })
settings:Description("Switch a built-in, or open Theme Editor for per-role colour wheels.")
 
local themePicker = settings:Dropdown({
    Text = "Built-in theme",
    Options = Ember.ThemeNames(),
    Default = Ember.CurrentTheme or "Dark",
    Save = "theme",
    Reapply = false,
    Callback = function(name) Ember.SetTheme(name) end,
})
 
local liveTheme = settings:Status({
    Text = "Live theme",
    Default = Ember.CurrentTheme or "Dark",
})
 
-- The chooser follows the theme changing from anywhere else, so it can never
-- name one thing while the window wears another.
Ember.OnThemeApplied(function(name)
    liveTheme:Set(name)
    if themePicker:Get() ~= name then themePicker:Set(name, true) end
end, win)
 
settings:Button({
    Text = "Random accent",
    ButtonText = "Shuffle",
    ButtonIcon = "sparkles",
    Style = "soft",
    Click = { Icon = "check", Hold = 0.9 },
    Callback = function()
        Ember.SetTheme({ accent = Color3.fromHSV(math.random(), 0.72, 0.95) })
        say("Accent shuffled", "droplet", "accent")
    end,
})
 
-- Only offered when the executor can actually write. Showing the buttons with
-- a note explaining why they will not work asks the reader to solve something
-- they cannot solve.
if Ember.Store.available() then
    local advanced = settings:Group({ Text = "Advanced", Icon = "wrench", Open = false })
 
    advanced:Button({
        Text = "Flush saved settings",
        Description = "Writes now instead of waiting out the debounce.",
        ButtonText = "Flush",
        Callback = function()
            local ok = Ember.Persist.flush()
            say(ok and "Settings written" or "Could not write", "save", ok and "muted" or "danger")
        end,
    })
 
    advanced:Button({
        Text = "Clear saved settings",
        Description = "Everything goes back to its default on the next run.",
        ButtonText = "Forget",
        Danger = true,
        Callback = function()
            Ember.Persist.forget()
            say("Saved settings cleared", "trash-2", "danger")
        end,
    })
end
 
settings:Separator()
settings:Status({
    Text = "Library",
    Default = "Ember " .. tostring(Ember.Version or "") .. " · 9 themes · colour wheels",
})
 
win:ThemeEditor({ Name = "Theme Editor", Icon = "droplet" })
 
--=============================================================================
-- CLEANUP
--=============================================================================
 
-- RevertOnClose already runs each toggle's off half when the window closes.
-- This is the belt-and-braces for anything not driven by a control.
win:OnDestroy(function()
    stopFly()
    stopInfiniteJump()
    stopNoclip()
    stopRainbow()
    stopTrail()
    clearESP()
    setFullbright(false)
    setFov(70)
end)
 
say("Ready")