KyriLib - Roblox UI Library
KyriLib is a lightweight Roblox UI library built for executor scripts. it gives you a fully featured window with tabs, elements, animations, and a built-in config system in a single loadstring.
most Roblox GUI libraries are bloated or painful to theme. KyriLib keeps it clean: dark base, 5 preset themes, per-property color pickers in the Settings tab, and a config save/load system that works out of the box with no extra setup.
get started githubwhat is a Roblox UI library?
a Roblox UI library is a tool that lets developers create graphical interfaces like menus, buttons, sliders, and dropdowns inside their scripts without building everything from scratch. instead of writing hundreds of lines of Roblox GUI code by hand, you load one script and call simple functions to build your interface.
KyriLib is built specifically for executor scripts. it handles all the rendering, theming, input handling, and config saving so you can focus on writing the actual features of your script.
why KyriLib
- one loadstring, everything included
- built-in config system with auto-load on startup
- 5 preset themes plus a full per-property theme editor
- works on mobile and desktop executors
- 1,000+ built-in icons via Lucide
- no dependencies, no external UI frameworks
features
- buttons, toggles, sliders, inputs, dropdowns, multiselects, color pickers, keybinds
- progress bars and image elements
- searchable dropdowns
- sliders with draggable track and click-to-type value input
- notifications with timer bar and click-to-dismiss
- 5 built-in preset themes, full per-property theme editor in Settings
- built-in save/load config system with auto-load support
- draggable and resizable window
- keybind system with press or hold modes, supports mouse buttons
- tab icons via 1,000+ lucideblox names, rbxassetid://, rbxthumb://, or https://
- mobile support
installation
local kyri = loadstring(game:HttpGet("https://raw.githubusercontent.com/Justanewplayer19/KyriLib/refs/heads/main/source.lua"))()
basic usage
local kyri = loadstring(game:HttpGet("https://raw.githubusercontent.com/Justanewplayer19/KyriLib/refs/heads/main/source.lua"))()
local w = kyri.new("my script", {
GameName = "MyGame",
AutoLoad = "default"
})
local main = w:tab("Main", "sword")
main:button("click me", function()
w:notify("hey", "button works", 2)
end)
main:toggle("enable thing", false, function(state)
print(state)
end, "thing")
main:slider("walkspeed", 0, 500, 16, function(val)
game.Players.LocalPlayer.Character.Humanoid.WalkSpeed = val
end, "ws")
window
kyri.new(title, options)
| option | type | description |
|---|---|---|
| GameName | string | used for config file storage |
| AutoLoad | string | config name to load on startup |
| Theme | table | override theme colors at init (any subset) |
local w = kyri.new("my script", {
GameName = "MyGame",
AutoLoad = "default",
Theme = {
accent = Color3.fromRGB(255, 110, 150)
}
})
window methods
w:tab(name, icon) -- create tab, returns tab object
w:notify(title, text, duration) -- send notification
w:accent(color) -- change accent color live
w:apply_theme(overrides) -- change any theme colors live
w:destroy() -- destroy the window
toggle visibility
press RightControl to show/hide the window.
tabs
w:tab(name, icon)
icon accepts a LucideBlox name, a raw rbxassetid://, a rbxthumb://, or an https:// URL:
w:tab("Combat", "crosshair") -- lucide icon name
w:tab("Players", "users")
w:tab("Settings", "settings-2")
w:tab("Custom", "rbxassetid://7734053495") -- raw roblox asset id
w:tab("Thumb", "rbxthumb://type=Asset&id=123&w=150&h=150")
w:tab("Web", "https://example.com/icon.png") -- https url (see note below)
1,000+ Lucide icons are built in. Pass the icon name as a string exactly as it appears on lucide.dev, e.g. "arrow-up-right", "battery-charging", "shield-check".
Common names: sword • axe • skull • flame • shield • crosshair • target • eye • ghost • users • user • crown • star • heart • settings • settings-2 • sliders • wrench • key • lock • map-pin • compass • home • search • filter • list • grid • music • mic • wifi • monitor • camera • video • file • folder • download • upload • save • trash • edit • bell • clock • info • alert-triangle • check • x • plus • terminal • bot • gamepad • gamepad-2
When you pass an https:// URL, KyriLib downloads the image in the background using the executor's request() function, caches it to disk, and loads it via getcustomasset(). The icon appears once the download finishes. Requires an executor that supports request() and getcustomasset() (Wave, Volt, Madium, etc.).
elements
button
tab:button(text, callback)
toggle
tab:toggle(text, default, callback, flag)
-- api: :set(state), :get(), :setcallback(fn)
slider
tab:slider(text, min, max, default, callback, flag, step)
-- step is optional. e.g. 0.1 for one decimal place, 0.25 for quarter steps
-- drag the track, or click the value label on the right to type a number directly
-- api: :set(val), :get(), :setcallback(fn)
main:slider("walkspeed", 0, 500, 16, function(val)
game.Players.LocalPlayer.Character.Humanoid.WalkSpeed = val
end, "ws")
main:slider("fov", 70, 120, 70, function(val)
-- decimal slider, step 0.1
end, "fov", 0.1)
input
tab:input(text, placeholder, callback, flag)
-- api: .input (the TextBox instance)
dropdown
tab:dropdown(text, options, default, callback, flag)
-- searchable: type in the box to filter options
-- api: :set(val)
multiselect
tab:multiselect(text, options, default, callback, flag)
-- callback receives a table of selected values
-- api: :set(val)
color picker
tab:colorpicker(text, default, callback, flag)
-- HSV picker, click the swatch to open
-- api: :set(color), :get()
keybind
tab:keybind(text, default, hold_to_interact, callback, flag)
-- click the box and press any key to rebind
progress bar
local pb = tab:progressbar(text, max)
pb:set(value, animated) -- animated is optional boolean
image
tab:image(asset_id, height) -- height defaults to 120
layout helpers
tab:section(text) -- divider with label
tab:label(text) -- plain text line
tab:paragraph(title, body) -- titled text block
tab:space(height) -- empty gap, default 8px
keybinds
press to trigger
main:keybind("fly key", "Q", false, function()
-- fires once on press
end, "fly_key")
hold to activate
main:keybind("speed boost", "LeftShift", true, function(holding)
if holding then
-- key held down
else
-- key released
end
end, "boost_key")
click the keybind element and press any key to rebind. saved to config automatically if flag is provided.
notifications
w:notify(title, text, duration)
notifications slide in from the right with a timer bar that drains over the duration. click a notification to dismiss it early.
w:notify("done", "script loaded", 2)
w:notify("error", "something went wrong", 5)
themes
preset themes
5 built-in presets: kyri, midnight, rose, forest, slate
w:apply_theme(kyri.presets["midnight"])
w:apply_theme(kyri.presets["rose"])
partial override
pass any subset of theme keys, only those colors change:
w:apply_theme({ accent = Color3.fromRGB(255, 80, 80) })
w:apply_theme({ bg = Color3.fromRGB(5, 5, 8), accent = Color3.fromRGB(80, 220, 120) })
theme keys
| key | what it affects |
|---|---|
| bg | main window background |
| container | header bar, sidebar |
| element | buttons, rows, inputs |
| hover | hover state color |
| active | active state color |
| accent | highlights, fill, indicators |
| text | primary text |
| subtext | secondary text, labels |
| border | UIStroke borders |
the auto-generated Settings tab includes a preset dropdown and individual color pickers for every theme property.
config system
elements with a flag string are saved/loaded automatically. a Settings tab is created with save/load UI built in.
-- auto-load a config on startup
local w = kyri.new("title", { GameName = "MyGame", AutoLoad = "default" })
-- read a flag value
local speed = w.flags.ws
-- set a value and fire its callback
w.flags.ws_set(100, true)
configs are stored per-game using GameName. Color3 values serialize correctly.
complete example
local kyri = loadstring(game:HttpGet("https://raw.githubusercontent.com/Justanewplayer19/KyriLib/refs/heads/main/source.lua"))()
local w = kyri.new("prison life", {
GameName = "PrisonLife",
AutoLoad = "default"
})
local main = w:tab("Main", "sword")
local misc = w:tab("Misc", "settings")
main:section("movement")
main:toggle("fly", false, function(state)
w:notify("fly", state and "on" or "off", 2)
end, "fly")
main:slider("walkspeed", 16, 500, 16, function(val)
game.Players.LocalPlayer.Character.Humanoid.WalkSpeed = val
end, "ws")
main:slider("jump power", 50, 500, 50, function(val)
game.Players.LocalPlayer.Character.Humanoid.JumpPower = val
end, "jp")
main:space()
main:section("teleport")
main:dropdown("location", {"spawn", "prison", "criminal base"}, "spawn", function(val)
w:notify("teleport", "going to " .. val, 2)
end)
misc:section("visual")
misc:colorpicker("accent color", kyri.theme.accent, function(c)
w:accent(c)
end, "accent")
misc:space()
misc:section("theme presets")
misc:button("midnight", function() w:apply_theme(kyri.presets["midnight"]) end)
misc:button("rose", function() w:apply_theme(kyri.presets["rose"]) end)
misc:button("default", function() w:apply_theme(kyri.presets["kyri"]) end)