Start typing to search packages!
uiservice
By @realstencer
Roblox
Mirroreduiservice
uiservice is a small helper framework for Roblox UI built on top of React, ReactRoblox, Ripple, and ReactCharm.
It keeps the original libraries available, but adds a simpler layer for the repetitive parts:
- quick element creation with
uiservice.e - ready-made UI constructors in
uiservice.componentsusing Roblox instance names - automatic default props when you call
e("TextLabel", { ... })ore(TextLabel, { ... }) - optional prop presets in
uiservice.props - optional helpers in
uiservice.values - easy mounting with
uiservice.mount - lightweight Charm-backed stores with
uiservice.createStore - Ripple bindings for React with
uiservice.useSpring,uiservice.useTween, anduiservice.useMotion
This package is meant to be a helper and easy starting point. It is not a replacement for React, ReactRoblox, Ripple, or Charm.
Install
[dependencies]
uiservice = "realstencer/uiservice@0.1.0"
What It Exports
local UIService = require(Packages.uiservice)
local React = UIService.React
local e = UIService.e
local TextLabel = UIService.TextLabel
local TextButton = UIService.TextButton
local TextBox = UIService.TextBox
local CanvasGroup = UIService.CanvasGroup
local ScreenGui = UIService.ScreenGui
local UICorner = UIService.UICorner
Main exports:
ReactReactRobloxReactCharmRippleCharme(component, props, children?)createComponent(className, defaults?)componentspropsvalues- Roblox-named built-ins directly on
UIService, such asTextLabel,TextButton,TextBox,CanvasGroup,ViewportFrame,VideoFrame,Frame,ScreenGui,UICorner,UIPadding,UIListLayout,UIGridLayout,UIPageLayout, andUIStroke - top-level helpers like
FontFace,AnchorPoint,Position, andSize mount(target, element)unmount(target)createRoot(target)createStore(initialState)createAtom(initialValue, options?)createComputed(callback, options?)useAtom(atomOrSelector, dependencies?)useSpring(initialValue, options?, dependencies?)useTween(initialValue, options?, dependencies?)useMotion(initialValue, options?, dependencies?)useAnimatedBinding(initialValue, factory, dependencies?)useScaleButton(options?)
Why Use It
Use uiservice when you want to keep real Roblox names like TextLabel, TextButton, ImageButton, UICorner, and UIPadding, but still move faster.
It helps in three main ways:
componentsgives you Roblox-named constructors such asui.TextLabelandui.TextButtonpropsgives you a basic ordered set of common properties for each instancevaluesgives you autocomplete-friendly helpers forColor3,Font,UDim2, size, position, anchor points, and common UI enums
Example: Simple TextLabel
local UIService = require(Packages.uiservice)
local e = UIService.e
local TextLabel = UIService.TextLabel
local element = e(TextLabel, {
AnchorPoint = Vector2.new(0.5, 0.5),
Position = UDim2.fromScale(0.5, 0.1),
Size = UDim2.fromScale(0.4, 0.08),
Text = "Title",
TextColor3 = Color3.fromRGB(255, 255, 255),
FontFace = Font.fromName("Montserrat"),
})
The automatic default props for TextLabel are still applied even if you only override a few fields. The current default set is based on src/Props.luau.
More Supported Classes
The helper now includes automatic presets for:
FrameTextLabelTextButtonTextBoxImageLabelImageButtonScrollingFrameCanvasGroupViewportFrameVideoFrameScreenGuiUICornerUIPaddingUIListLayoutUIGridLayoutUIPageLayoutUIAspectRatioConstraintUISizeConstraintUIScaleUIStrokeUIGradient
Example: Using Direct Roblox Names
local UIService = require(Packages.uiservice)
local e = UIService.e
local TextLabel = UIService.TextLabel
local TextButton = UIService.TextButton
local ScreenGui = UIService.ScreenGui
local UICorner = UIService.UICorner
local function MainMenu()
return e(ScreenGui, {
DisplayOrder = 10,
}, {
Title = e(TextLabel, {
AnchorPoint = Vector2.new(0.5, 0),
Position = UDim2.fromScale(0.5, 0.08),
Size = UDim2.fromScale(0.4, 0.08),
Text = "Main Menu",
TextColor3 = Color3.fromRGB(255, 255, 255),
FontFace = Font.fromName("Montserrat"),
TextScaled = true,
}),
PlayButton = e(TextButton, {
AnchorPoint = Vector2.new(0.5, 0.5),
Position = UDim2.fromScale(0.5, 0.5),
Size = UDim2.fromOffset(220, 54),
BackgroundColor3 = Color3.fromRGB(66, 135, 245),
Text = "Play",
TextColor3 = Color3.fromRGB(255, 255, 255),
onActivated = function()
print("Play clicked")
end,
}, {
Corner = e(UICorner, {
CornerRadius = UDim.new(0, 10),
}),
}),
})
end
Example: Optional Preset Builder
If you do want a prefilled ordered prop table, props is still available:
local props = UIService.props
local TextLabel = UIService.TextLabel
local Title = e(TextLabel, props.TextLabel({
Text = "Title",
FontFace = Font.fromName("Montserrat"),
}))
Example: Mount To PlayerGui
local Players = game:GetService("Players")
local UIService = require(Packages.uiservice)
local playerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
UIService.mount(playerGui, MainMenu())
Example: Game State With ReactCharm
local UIService = require(Packages.uiservice)
local store = UIService.createStore({
coins = 0,
menuOpen = true,
selectedTab = "Home",
})
store.computed("title", function()
return store.get("selectedTab") .. " Menu"
end)
local function Header()
local coins = store.use("coins")
local title = store.use("title")
return UIService.e(UIService.TextLabel, {
BackgroundTransparency = 1,
Size = UDim2.new(1, 0, 0, 36),
Text = string.format("%s | Coins: %d", title, coins),
TextColor3 = Color3.fromRGB(255, 255, 255),
TextScaled = false,
TextSize = 22,
})
end
store.set("coins", function(value)
return value + 50
end)
Example: Ripple Animation In React
local UIService = require(Packages.uiservice)
local React = UIService.React
local e = UIService.e
local TextButton = UIService.TextButton
local UICorner = UIService.UICorner
local function AnimatedPlayButton()
local scale, spring, buttonProps = UIService.useScaleButton({
hoverScale = 1.04,
pressScale = 0.95,
})
return e(TextButton, {
AnchorPoint = Vector2.new(0.5, 0.5),
Position = UDim2.fromScale(0.5, 0.5),
Size = scale:map(function(value)
return UDim2.fromOffset(240 * value, 64 * value)
end),
BackgroundColor3 = Color3.fromRGB(76, 201, 126),
Text = "Play",
TextColor3 = Color3.fromRGB(18, 24, 18),
TextScaled = true,
AutoButtonColor = false,
[React.Change.GuiState] = buttonProps[React.Change.GuiState],
Activated = function()
spring:setGoal(1.08)
task.delay(0.08, function()
spring:setGoal(1)
end)
end,
}, {
Corner = e(UICorner, {
CornerRadius = UDim.new(0, 12),
}),
})
end
Full Example: Animated Hover And Press Button
This is the pattern for a button that grows on hover and compresses on press.
local UIService = require(Packages.uiservice)
local React = UIService.React
local e = UIService.e
local TextButton = UIService.TextButton
local UICorner = UIService.UICorner
local UIStroke = UIService.UIStroke
local function SpringButton(props)
local scale, spring, hoverProps = UIService.useScaleButton(UIService.props.TextButtonHoverScale({
hoverScale = 1.05,
pressScale = 0.93,
restScale = 1,
}))
return e(TextButton, {
AnchorPoint = Vector2.new(0.5, 0.5),
Position = props.Position or UDim2.fromScale(0.5, 0.5),
Size = scale:map(function(value)
return UDim2.fromOffset(220 * value, 56 * value)
end),
BackgroundColor3 = props.BackgroundColor3 or Color3.fromRGB(66, 135, 245),
Text = props.Text or "Play",
TextColor3 = Color3.fromRGB(255, 255, 255),
FontFace = Font.fromName("Montserrat"),
[React.Change.GuiState] = hoverProps[React.Change.GuiState],
Activated = function()
spring:setGoal(0.9)
task.delay(0.06, function()
spring:setGoal(1)
end)
if props.Activated then
props.Activated()
end
end,
}, {
Corner = e(UICorner, {
CornerRadius = UDim.new(0, 12),
}),
Stroke = e(UIStroke, {
Color = Color3.fromRGB(255, 255, 255),
Transparency = 0.35,
}),
})
end
Full Example: Shop UI With State And Animation
local UIService = require(Packages.uiservice)
local React = UIService.React
local e = UIService.e
local ScreenGui = UIService.ScreenGui
local Frame = UIService.Frame
local TextLabel = UIService.TextLabel
local TextButton = UIService.TextButton
local UIListLayout = UIService.UIListLayout
local UIPadding = UIService.UIPadding
local UICorner = UIService.UICorner
local UIStroke = UIService.UIStroke
local store = UIService.createStore({
coins = 500,
isPurchasing = false,
errorMessage = nil,
})
local function ShopButton(props)
local scale, spring, hoverProps = UIService.useScaleButton({
hoverScale = 1.04,
pressScale = 0.95,
})
return e(TextButton, {
Size = scale:map(function(value)
return UDim2.fromOffset(260 * value, 52 * value)
end),
BackgroundColor3 = props.BackgroundColor3 or Color3.fromRGB(66, 135, 245),
Text = props.Text,
TextColor3 = Color3.fromRGB(255, 255, 255),
FontFace = Font.fromName("Montserrat"),
[React.Change.GuiState] = hoverProps[React.Change.GuiState],
Activated = function()
spring:setGoal(0.92)
task.delay(0.06, function()
spring:setGoal(1)
end)
props.Activated()
end,
}, {
Corner = e(UICorner, {
CornerRadius = UDim.new(0, 10),
}),
})
end
local function ShopView()
local coins = store.use("coins")
local isPurchasing = store.use("isPurchasing")
local errorMessage = store.use("errorMessage")
return e(ScreenGui, {}, {
Root = e(Frame, {
AnchorPoint = Vector2.new(0.5, 0.5),
Position = UDim2.fromScale(0.5, 0.5),
Size = UDim2.fromScale(0.34, 0.42),
BackgroundColor3 = Color3.fromRGB(25, 28, 34),
}, {
Corner = e(UICorner, {
CornerRadius = UDim.new(0, 14),
}),
Stroke = e(UIStroke, {
Color = Color3.fromRGB(255, 255, 255),
Transparency = 0.6,
}),
Padding = e(UIPadding, {
PaddingTop = UDim.new(0, 16),
PaddingBottom = UDim.new(0, 16),
PaddingLeft = UDim.new(0, 16),
PaddingRight = UDim.new(0, 16),
}),
Layout = e(UIListLayout, {
Padding = UDim.new(0, 10),
}),
Title = e(TextLabel, {
Size = UDim2.new(1, 0, 0, 34),
Text = string.format("Coins: %d", coins),
TextColor3 = Color3.fromRGB(255, 255, 255),
TextScaled = false,
TextSize = 26,
FontFace = Font.fromName("Montserrat", Enum.FontWeight.Bold),
}),
BuySword = e(ShopButton, {
Text = isPurchasing and "Purchasing..." or "Buy Sword - 200",
Activated = function()
if isPurchasing then
return
end
store.batch(function()
store.set("isPurchasing", true)
store.set("errorMessage", nil)
end)
if coins < 200 then
store.batch(function()
store.set("isPurchasing", false)
store.set("errorMessage", "Not enough coins")
end)
return
end
task.delay(0.2, function()
store.batch(function()
store.set("coins", function(value)
return value - 200
end)
store.set("isPurchasing", false)
end)
end)
end,
}),
Error = errorMessage and e(TextLabel, {
Size = UDim2.new(1, 0, 0, 24),
Text = errorMessage,
TextColor3 = Color3.fromRGB(255, 120, 120),
TextScaled = false,
TextSize = 18,
}) or nil,
}),
})
end
For a real game, replace that local coin deduction with a server purchase request and update the store from the server response.
Why There Is No Separate Types Module
There used to be a separate Types module during an earlier iteration, but it was removed because the Luau analyzer in this workspace handled those cross-module type imports badly. The public helper types are now exported directly from uiservice itself, which keeps the package simpler and avoids those toolchain issues.
Example: Font And Stroke Defaults
local UIService = require(Packages.uiservice)
local e = UIService.e
local TextLabel = UIService.TextLabel
local UIStroke = UIService.UIStroke
local Label = e(TextLabel, {
Text = "Hello",
FontFace = Font.fromName("Montserrat"),
})
local Stroke = e(UIStroke, {
Color = Color3.fromRGB(255, 255, 255),
})
Notes
componentsnow keeps Roblox instance names instead of renaming them.e(TextLabel, { ... })now applies the built-in default prop set automatically for supported Roblox UI classes.props.TextLabel(),props.TextButton(), and similar helpers are optional now, not required.FontFacesupport is available throughFont.fromName(...), andUIStrokedefaults now useStrokeSizingMode = Enum.StrokeSizingMode.ScaledwithThickness = 0.05.components.MenuaddsUICorner,UIPadding, andUIListLayoutautomatically unless you override them inchildren.- More built-in Roblox UI classes now have presets, including
TextBox,CanvasGroup,ViewportFrame,VideoFrame,UIGridLayout,UIPageLayout,UISizeConstraint,UIScale, andUIGradient. useSpring,useTween, anduseMotionreturn a React binding plus the underlying Ripple motor.createStoreis intentionally small. It helps with UI state fast, without hiding Charm itself.
Recommended Direction
Use uiservice as a thin layer, not a replacement for the original libraries. If a screen needs something more advanced, you can always drop down to React, ReactRoblox, Ripple, or Charm directly because they are still exported.
Package Details
Install command (Click to copy)
Version
0.2.0
License
MIT
Safe for commercial use
Automated license review — not legal advice.
