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.
Ember
live showcase
Enabled
FireOnStart runs the callback once at build time.
Speed
Panic key
Outlined
The house style, and the default.
Save configuration
Delete config
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#
--!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")