LogoObsidian

Library

The Library contains all essential functions and data used to create and get data from the UI.


Window

Obsidian

The Window object is your base UI container. It hosts tabs, groupboxes and mostly everything else driven by the library. The next step to using the library is to create a tab inside the window.

Usage

Create a window with Library:CreateWindow() and override any defaults you need:

local Window = Library:CreateWindow({
    Title = "mspaint",
    Footer = "version: example",
    Icon = 95816097006870,
    NotifySide = "Right",
})

Prop

Type

Obsidian can expose a draggable handle that lets players resize the sidebar at runtime. Enable it and tweak the behaviour directly from your window configuration:

local Window = Library:CreateWindow({
    Title = "mspaint",
    EnableSidebarResize = true,
 
    -- Optional Sidebar Settings
    MinSidebarWidth = 200, -- stop shrinking when the sidebar hits 200px
    SidebarCompactWidth = 56,
})

All window instances expose helpers for responding to layout changes or driving your own resizing logic.

GetSidebarWidth

Returns the current sidebar width in pixels.

local CurrentWidth = Window:GetSidebarWidth()

IsSidebarCompacted

Checks if the sidebar is currently in compact (icon-only) mode.

if Window:IsSidebarCompacted() then
    print("Sidebar is collapsed")
end

SetSidebarWidth

Programmatically resize the sidebar. Values outside the configured bounds are clamped automatically.

Window:SetSidebarWidth(240)
Arg IdxArgument DescriptionTypeDefault
1Desired sidebar width in pixelsnumberWidth

SetCompact

Toggle compact mode explicitly. Pass true to force compact, or false to restore the last expanded width.

Window:SetCompact(true)
Arg IdxArgument DescriptionTypeDefault
1Whether the sidebar should stay compactedboolean

ApplyLayout

Re-apply all sidebar measurements.

Window:ApplyLayout()

Notifications

notification

Use Library:Notify() for quick, non-blocking feedback. Notifications support:

  • Simple timed popups.
  • Persistent messages you can update or destroy.
  • Progress indicators with step counters.
  • Optional sounds or other custom behavior based on your own logic.

Creating a notification

Choose between positional arguments for quick calls or a configuration table for full control.

Regular parameters

Library:Notify("Hello world!", 4)
Arg IdxArgument DescriptionTypeDefault
1Description of the notificationstring"nil"
2Amount of time to show the notification fornumber | instance4
3SoundId to play when the notification is shownnumbernil

Table parameters

Pick an example that matches your use case:

Library:Notify({
    Title = "mspaint",
    Description = "Hello world!",
    Time = 4,
})

Prop

Type

Methods

ChangeTitle

Update the notification title without recreating it.

Notification:ChangeTitle("New Title")
Arg IdxArgument DescriptionTypeDefault
1New title of the notificationstringnil

ChangeDescription

Refresh the supporting text while keeping the notification open.

Notification:ChangeDescription("New Description")
Arg IdxArgument DescriptionTypeDefault
1New description of the notificationstringnil

ChangeStep

Advance or rewind the progress bar when using step-based notifications.

Notification:ChangeStep(5)
Arg IdxArgument DescriptionTypeDefault
1New step of the progress notificationnumbernil

Destroy

Immediately dismiss the notification and free its resources.

Notification:Destroy()

Watermark

Watermarks are now deprecated. Please use Library:AddDraggableLabel instead.


Draggable Labels

watermark

Draggable Labels are compact, draggable overlays containing text. They are ideal for surfacing information such as FPS, ping, server info, etc. The feature is inspired by the LinoriaLib UI Library Watermark feature.

Methods

AddDraggableLabel

Adds a draggable label to the UI.

Library:AddDraggableLabel("Obsidian demo")
Arg IdxArgument DescriptionTypeDefault
1Text to display in the draggable labelstringnil

SetText

Sets the draggable label text.

local DraggableLabel = Library:AddDraggableLabel("Obsidian demo")
DraggableLabel:SetText("Obsidian demo v2")
Arg IdxArgument DescriptionTypeDefault
1Text to display in the draggable labelstringnil

SetVisible

Sets the draggable label visibility.

local DraggableLabel = Library:AddDraggableLabel("Obsidian demo")
DraggableLabel:SetVisible(false)
Arg IdxArgument DescriptionTypeDefault
1Whether to show the draggable labelbooleantrue

Example

-- Sets the draggable label visibility
local DraggableLabel = Library:AddDraggableLabel("Obsidian demo")
DraggableLabel:SetVisible(true)
 
-- Example of dynamically-updating draggable label with common traits (fps and ping)
local FrameTimer = tick()
local FrameCounter = 0;
local FPS = 60;
 
local WatermarkConnection = game:GetService('RunService').RenderStepped:Connect(function()
    FrameCounter += 1;
 
    if (tick() - FrameTimer) >= 1 then
        FPS = FrameCounter;
        FrameTimer = tick();
        FrameCounter = 0;
    end;
 
    DraggableLabel:SetText(('Obsidian demo | %s fps | %s ms'):format(
        math.floor(FPS),
        math.floor(game:GetService('Stats').Network.ServerStatsItem['Data Ping']:GetValue())
    ));
end);

Keybinds Menu

keybinds

The keybinds menu surfaces every registered keybind alongside its current state. When a keybind is configured in Toggle mode the menu also renders tap-friendly buttons, giving mobile players parity with keyboard users.

Library.ShowToggleFrameInKeybinds = true -- Show toggle state in keybind menu

Custom Cursor

custom cursor

Enable the custom cursor to render the Obsidian-styled pointer at your mouse position—handy for experiences that hide or replace Roblox's default cursor.

Library.ShowCustomCursor = true

Icons

Icons originate from the lucide icon pack. You can change the icon library so long as you call it before creating any UI elements and it follows the expected return data.

local Library = require(game:GetService("ReplicatedStorage"):WaitForChild("Obsidian"))
local Icons = require(game:GetService("ReplicatedStorage"):WaitForChild("Lucide"))
 
-- Set Library Icon Module
Library:SetIconModule(Icons)

The direct lucide module can be found here. (Our automation updates the icon spritesheet each month)

Custom Icon Registry

If you'd like to make your own custom Icon Module, make sure it follows these types:

type Icon = {
    Url: string,
    Id: number,
    IconName: string,
    ImageRectOffset: Vector2,
    ImageRectSize: Vector2,
}
 
type IconModule = {
    Icons: { string },
    GetAsset: (Name: string) -> Icon?,
}
 
local Icons: IconModule = {
    Icons: {}
}
 
function Icons.GetAsset(Name: string)
    return nil
end
 
return Icons

Obsidian is dependent on a few icons to be able to be displayed properly. Please make sure you have icons named: check (Toggles), chevron-up (Dropdowns), move-diagonal-2 (Window Resizing Icon bottom right of the window), key (Key System Tab Icon), search (Searchbar), move (Window movement Icon top right of the window)

Custom Asset Icons

If you'd like to use custom hosted images (like those on Github) with a Roblox Asset ID as a fallback, you can use the built-in ImageManager:

local ImageManager = Library.ImageManager

AddAsset

Adds a custom asset to the ImageManager

ImageManager.AddAsset("mspaint_logo", 95816097006870, "https://www.mspaint.cc/icon.png")
Arg IdxArgument DescriptionTypeDefault
1Asset Namestringnil
2Roblox Asset IDnumbernil
3Asset URLstringnil
4Force Redownloadboolean?nil

GetAsset

Retrieves the asset ID for the provided asset

local AssetID = ImageManager.GetAsset("mspaint_logo")
Arg IdxArgument DescriptionTypeDefault
1Asset Namestringnil

DownloadAsset

Downloads the asset image to the workspace folder

This runs automatically in AddAsset, so you don't need to call it separately (unless you want to redownload the asset image)

ImageManager.DownloadAsset("mspaint_logo")
Arg IdxArgument DescriptionTypeDefault
1Asset Namestringnil
2Force Redownloadboolean?nil

In Obsidian, there is a helper field that you can set that allows you to easily bind a Keybind to toggle the main window.

MenuGroup:AddLabel("Menu bind"):AddKeyPicker("MenuKeybind", {
    Default = "RightShift",
    NoUI = true,
    Text = "Menu keybind"
})
 
Library.ToggleKeybind = Options.MenuKeybind