A lightweight, strictly-typed reactive UI library for Roblox that combines the best of Fusion and Vide. Zero dependencies. Performant.
- Reactive System: Automatic dependency tracking with fine-grained updates
- Strict Typing: Full
--!strictsupport with complete type safety - Spring Animations: Built-in spring physics for smooth, natural animations
- Component System: Reusable components with the
Establishpattern - Zero Dependencies: Standalone library, just drop it in and start building
- Performance: Native-optimized functions with
@nativeannotations
Add to your wally.toml:
[dependencies]
obsidian = "veraci-ty/[email protected]"Then run:
wally install- Download the latest release from GitHub Releases
- Extract the
Obsidianfolder - Place it in your
src/ReplicatedStorage/Packages/directory - Add to your
default.project.json:
{
"name": "project",
"tree": {
"$className": "DataModel",
"ReplicatedStorage": {
"$className": "ReplicatedStorage",
"Packages": {
"$className": "Folder",
"Obsidian": {
"$path": "src/ReplicatedStorage/Packages/Obsidian"
}
}
}
}
}- Download the
.rbxmfile from GitHub Releases - Import into Roblox Studio
- Place in
ReplicatedStorage.Packages
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Obsidian = require(ReplicatedStorage.Packages.Obsidian)
local Players = game:GetService("Players")
local playerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
local screenGui = Instance.new("ScreenGui")
screenGui.Parent = playerGui
Obsidian.attach(function()
return Obsidian.new "Frame" {
Size = UDim2.fromScale(1, 1),
BackgroundColor3 = Color3.fromRGB(15, 17, 22),
[Obsidian.Children] = {
Obsidian.new "TextLabel" {
Size = UDim2.fromScale(1, 1),
Text = "Hello, Obsidian!",
TextColor3 = Color3.new(1, 1, 1),
BackgroundTransparency = 1,
},
},
}
end, screenGui)Full documentation is available at: https://useobsidian.dev
Reactive Sources
local count = Obsidian.source(0)
print(count()) --> 0
count(5)
print(count()) --> 5Derived Values
local count = Obsidian.source(0)
local doubled = Obsidian.derive(function()
return count() * 2
end)Effects
local name = Obsidian.source("World")
Obsidian.effect(function()
print("Hello, " .. name() .. "!")
end)Spring Animations
local pos = Obsidian.source(0)
local smooth = Obsidian.spring(pos, 0.4, 0.8)
Obsidian.new "Frame" {
Position = function()
return UDim2.fromOffset(smooth(), 0)
end,
}Components
Obsidian:Establish("Button", function(props)
return Obsidian.new "TextButton" {
Size = UDim2.fromOffset(160, 44),
Text = props.Text or "Button",
Activated = props.OnClick,
}
end)
Obsidian.new "Button" { Text = "Click Me" }source(initial)- Create a reactive sourcederive(fn)- Create a derived reactive valuecomputed(fn)- Alias forderiveeffect(fn)- Run side effects on changeValue(initial)- State object withget,set,updatemethodsspring(input, period?, damping?)- Smooth spring animationspeek(value)- Read without trackinguntrack(fn)- Execute without tracking dependenciesbatch(fn)- Batch reactive updatesroot(fn)- Create reactive root with manual cleanupcleanup(fn)- Register cleanup function
new "ClassName" { ... }- Create instances with reactive propertiesChildren- Special key for nesting child instancesParent- Reactive parent propertyOnDestroy- Cleanup callbacksRef- Reference callbacksattach(render, parent)- Alias formountapply(instance)- Apply props to existing instance
Establish(name, factory)- Register reusable components
map(list, fn)- Map over a listcompact(list)- Remove nil values
- Roblox Studio or Roblox runtime
- Luau (Roblox's Lua variant)
MIT License - see LICENSE file for details
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
- Documentation: https://obsidian-ui.github.io
- Wally Package:
veraci-ty/obsidian - Issues: GitHub Issues
Obsidian takes inspiration from: