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 github

what 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)

optiontypedescription
GameNamestringused for config file storage
AutoLoadstringconfig name to load on startup
Themetableoverride 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)
lucideblox icon pack

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: swordaxeskullflameshieldcrosshairtargeteyeghostusersusercrownstarheartsettingssettings-2sliderswrenchkeylockmap-pincompasshomesearchfilterlistgridmusicmicwifimonitorcameravideofilefolderdownloaduploadsavetrasheditbellclockinfoalert-trianglecheckxplusterminalbotgamepadgamepad-2

https:// urls

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")
info

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

keywhat it affects
bgmain window background
containerheader bar, sidebar
elementbuttons, rows, inputs
hoverhover state color
activeactive state color
accenthighlights, fill, indicators
textprimary text
subtextsecondary text, labels
borderUIStroke borders
settings tab

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)
info

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)