roblox-ui

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Roblox UI

Roblox UI

Foundations

基础

  • Put UI in
    StarterGui
    as
    ScreenGui
    s (copied to each player's
    PlayerGui
    ), or create it from a client controller. UI code is client-only; the server never touches
    PlayerGui
    in normal designs.
  • ScreenGui
    defaults to set:
    ResetOnSpawn = false
    (keep UI across deaths),
    ZIndexBehavior = Sibling
    ,
    IgnoreGuiInset
    per design,
    ScreenInsets = CoreUISafeInsets
    for interactive UI (clears notches and the Roblox top bar);
    DeviceSafeInsets
    /
    None
    only for full-bleed backgrounds.
  • Size and position with Scale (
    UDim2.fromScale
    ) plus constraints; use Offset only for fixed details (padding, strokes, icons). Pure-Offset UI breaks on phones and 4K screens.
  • AnchorPoint = Vector2.new(0.5, 0.5)
    +
    Position = UDim2.fromScale(0.5, 0.5)
    centers an element.
  • UIAspectRatioConstraint
    keeps shapes square/consistent;
    UISizeConstraint
    caps sizes;
    UITextSizeConstraint
    with
    TextScaled
    bounds text size (prefer fixed
    TextSize
    +
    AutomaticSize
    where possible —
    TextScaled
    produces inconsistent sizes).
  • AutomaticSize
    lets frames grow with content (lists, tooltips, chat bubbles).
  • Test every screen in the Device Emulator (phone portrait/landscape, tablet, console 10-foot, 4K).
  • 将 UI 作为
    ScreenGui
    放入
    StarterGui
    (会复制到每位玩家的
    PlayerGui
    ),或者由 客户端 controller 创建。UI 代码仅在客户端运行;正常设计中,服务端绝不操作
    PlayerGui
    。
  • ScreenGui
    默认应设置为:
    ResetOnSpawn = false
    (在死亡后保留 UI)、
    ZIndexBehavior = Sibling
    、 根据设计配置
    IgnoreGuiInset
    ;对于交互式 UI,使用
    ScreenInsets = CoreUISafeInsets
    (避开刘海和 Roblox 顶部栏);仅全屏铺满的背景才使用
    DeviceSafeInsets
    /
    None
    。
  • 使用 Scale(
    UDim2.fromScale
    )配合 constraints 控制尺寸和位置;仅将 Offset 用于固定 细节(padding、stroke、icon)。纯 Offset UI 会在手机和 4K 屏幕上失效。
  • AnchorPoint = Vector2.new(0.5, 0.5)
    与
    Position = UDim2.fromScale(0.5, 0.5)
    配合使用, 可将元素居中。
  • UIAspectRatioConstraint
    可保持形状方正或比例一致;
    UISizeConstraint
    可限制尺寸上限;
    UITextSizeConstraint
    与
    TextScaled
    可限制文字大小(尽可能优先使用固定
    TextSize
    +
    AutomaticSize
    ——
    TextScaled
    会产生不一致的尺寸)。
  • AutomaticSize
    可让 Frame 随内容扩展(列表、tooltip、聊天气泡)。
  • 在 Device Emulator 中测试每一种屏幕(手机竖屏/横屏、平板、主机 10-foot 视角、4K)。

Layout

布局

NeedUse
Rows/columns that adapt
UIListLayout
(
FillDirection
,
Padding
,
HorizontalFlex
/
VerticalFlex
,
Wraps
)
One item grows to fill space
UIFlexItem
child with
FlexMode = Fill
(or
Grow
/
Shrink
/
Custom
)
Grids (inventory)
UIGridLayout
inside a
ScrollingFrame
with
AutomaticCanvasSize
Carousels/pages
UIPageLayout
Rounded corners, borders, padding
UICorner
,
UIStroke
,
UIPadding
Gradients, shadows
UIGradient
,
UIShadow
Scale a whole group
UIScale
luau
--!strict
local Players = game:GetService("Players")

local playerGui = Players.LocalPlayer:WaitForChild("PlayerGui")

local screenGui = Instance.new("ScreenGui")
screenGui.Name = "Hud"
screenGui.ResetOnSpawn = false
screenGui.ScreenInsets = Enum.ScreenInsets.CoreUISafeInsets

local bar = Instance.new("Frame")
bar.Name = "Toolbar"
bar.AnchorPoint = Vector2.new(0.5, 1)
bar.Position = UDim2.new(0.5, 0, 1, -16)
bar.Size = UDim2.fromScale(0.6, 0.1)
bar.BackgroundTransparency = 0.3
bar.Parent = screenGui

local list = Instance.new("UIListLayout")
list.FillDirection = Enum.FillDirection.Horizontal
list.HorizontalFlex = Enum.UIFlexAlignment.Fill -- slots share the width equally
list.Padding = UDim.new(0, 8)
list.Parent = bar

Instance.new("UICorner").Parent = bar
local padding = Instance.new("UIPadding")
padding.PaddingLeft, padding.PaddingRight = UDim.new(0, 8), UDim.new(0, 8)
padding.Parent = bar

for slot = 1, 5 do
	local button = Instance.new("TextButton")
	button.Name = `Slot{slot}`
	button.Text = tostring(slot)
	button.Size = UDim2.fromScale(0, 1)
	button.Parent = bar
	Instance.new("UIAspectRatioConstraint").Parent = button
end

screenGui.Parent = playerGui -- parent last: one layout pass, no flicker
需求使用
自适应行/列
UIListLayout
(
FillDirection
、
Padding
、
HorizontalFlex
/
VerticalFlex
、
Wraps
)
让一个项扩展以填满空间使用
FlexMode = Fill
(或
Grow
/
Shrink
/
Custom
)的
UIFlexItem
子元素
网格(库存)在
ScrollingFrame
中使用
UIGridLayout
,并启用
AutomaticCanvasSize
轮播/分页
UIPageLayout
圆角、边框、内边距
UICorner
、
UIStroke
、
UIPadding
渐变、阴影
UIGradient
、
UIShadow
缩放整个组
UIScale
luau
--!strict
local Players = game:GetService("Players")

local playerGui = Players.LocalPlayer:WaitForChild("PlayerGui")

local screenGui = Instance.new("ScreenGui")
screenGui.Name = "Hud"
screenGui.ResetOnSpawn = false
screenGui.ScreenInsets = Enum.ScreenInsets.CoreUISafeInsets

local bar = Instance.new("Frame")
bar.Name = "Toolbar"
bar.AnchorPoint = Vector2.new(0.5, 1)
bar.Position = UDim2.new(0.5, 0, 1, -16)
bar.Size = UDim2.fromScale(0.6, 0.1)
bar.BackgroundTransparency = 0.3
bar.Parent = screenGui

local list = Instance.new("UIListLayout")
list.FillDirection = Enum.FillDirection.Horizontal
list.HorizontalFlex = Enum.UIFlexAlignment.Fill -- slots share the width equally
list.Padding = UDim.new(0, 8)
list.Parent = bar

Instance.new("UICorner").Parent = bar
local padding = Instance.new("UIPadding")
padding.PaddingLeft, padding.PaddingRight = UDim.new(0, 8), UDim.new(0, 8)
padding.Parent = bar

for slot = 1, 5 do
	local button = Instance.new("TextButton")
	button.Name = `Slot{slot}`
	button.Text = tostring(slot)
	button.Size = UDim2.fromScale(0, 1)
	button.Parent = bar
	Instance.new("UIAspectRatioConstraint").Parent = button
end

screenGui.Parent = playerGui -- parent last: one layout pass, no flicker

Styling: StyleSheets (CSS-like)

样式:StyleSheets(类似 CSS)

Roblox's engine-level styling replaces copy-pasted property values:
  • StyleSheet
    with
    StyleRule
    s (
    Selector
    like
    "TextButton"
    ,
    ".Primary"
    (tag),
    "#Close"
    (name),
    "TextButton:Hover"
    (state),
    "::UICorner"
    (modifier pseudo-instance)) and
    rule:SetProperties({...})
    .
  • Tokens are attributes on a token sheet (
    $Primary
    ,
    $Radius
    ); themes are sheets deriving tokens (
    StyleDerive
    ); swap themes by retargeting the
    StyleDerive
    .
  • A
    StyleLink
    under a
    ScreenGui
    applies one sheet to that tree. Style queries (
    @Name
    ) switch styles by screen size, input type, or accessibility settings.
  • Edit visually in Studio's Style Editor. Details and a code example: references/styling-and-frameworks.md.
Roblox 的引擎级样式功能可取代重复复制粘贴的属性值:
  • 使用带
    StyleRule
    s 的
    StyleSheet
    (
    Selector
    可写成
    "TextButton"
    、
    ".Primary"
    (tag)、
    "#Close"
    (name)、
    "TextButton:Hover"
    (state)、
    "::UICorner"
    (modifier pseudo-instance)),并通过
    rule:SetProperties({...})
    设置属性。
  • Tokens 是 token sheet 上的属性(
    $Primary
    、
    $Radius
    );themes 是派生自 tokens 的 sheet (
    StyleDerive
    );重新指定
    StyleDerive
    的目标即可切换 themes。
  • 放在
    ScreenGui
    下的
    StyleLink
    会将一个 sheet 应用于该 UI 树。Style queries(
    @Name
    ) 可按屏幕尺寸、输入类型或无障碍设置切换样式。
  • 可在 Studio 的 Style Editor 中进行可视化编辑。更多细节和代码示例: references/styling-and-frameworks.md。

Cross-platform input in UI

UI 中的跨平台输入

  • Read
    UserInputService.PreferredInput
    (
    KeyboardAndMouse
    ,
    Touch
    ,
    Gamepad
    ) and listen to
    UserInputService:GetPropertyChangedSignal("PreferredInput")
    to swap button prompts and layouts. Don't infer platform from
    TouchEnabled
    /
    KeyboardEnabled
    alone.
  • Use
    GuiButton.Activated
    (works for mouse, touch, and gamepad) instead of
    MouseButton1Click
    .
  • Gamepad/console: every interactive element
    Selectable
    , set
    GuiService.SelectedObject
    when a menu opens, group with
    SelectionGroup
    /
    NextSelection*
    for predictable D-pad navigation, support
    ButtonB
    to close. Minimum touch target ≈ 44×44 px; readable text ≥ 14 px on phones.
  • Bind actions through the Input Action System (
    InputBinding.UIButton
    makes an on-screen button trigger an action) — see
    roblox-input
    .
  • 读取
    UserInputService.PreferredInput
    (
    KeyboardAndMouse
    、
    Touch
    、
    Gamepad
    ),并监听
    UserInputService:GetPropertyChangedSignal("PreferredInput")
    ,以切换按钮提示和布局。 不要仅凭
    TouchEnabled
    /
    KeyboardEnabled
    推断平台。
  • 使用
    GuiButton.Activated
    (适用于 mouse、touch 和 gamepad),而不是
    MouseButton1Click
    。
  • 对于 gamepad/console:所有可交互元素都应设为
    Selectable
    ;菜单打开时设置
    GuiService.SelectedObject
    ;使用
    SelectionGroup
    /
    NextSelection*
    组织分组,以实现可预测的 D-pad 导航; 支持使用
    ButtonB
    关闭。触摸目标尺寸至少约为 44×44 px;手机上的可读文字应 ≥ 14 px。
  • 通过 Input Action System 绑定操作(
    InputBinding.UIButton
    可让屏幕按钮触发操作)——参见
    roblox-input
    。

Text

文本

  • RichText = true
    enables
    <b>
    ,
    <i>
    ,
    <font color="#FF0">
    ,
    <stroke>
    , etc. Escape user text.
  • Any text from one player shown to another must be filtered with
    TextService:FilterStringAsync
    on the server (
    roblox-text-chat
    ). That includes pet names, signs, guild names, trade notes.
  • Use
    FontFace = Font.new("rbxasset://fonts/families/GothamSSm.json", Enum.FontWeight.Bold)
    for weights.
  • Localize with
    LocalizationTable
    s and auto-translation; avoid baking text into images.
  • RichText = true
    可启用
    <b>
    、
    <i>
    、
    <font color="#FF0">
    、
    <stroke>
    等标签。请转义用户文本。
  • 任何由一名玩家显示给另一名玩家的文本,都必须在服务端使用
    TextService:FilterStringAsync
    进行过滤(
    roblox-text-chat
    )。这包括宠物名称、标牌、 公会名称和交易备注。
  • 使用
    FontFace = Font.new("rbxasset://fonts/families/GothamSSm.json", Enum.FontWeight.Bold)
    设置字重。
  • 使用
    LocalizationTable
    s 和自动翻译进行本地化;避免将文字固化在图片中。

Animation and feel

动画与手感

  • Tween on the client:
    TweenService:Create(frame, TweenInfo.new(0.2, Enum.EasingStyle.Quad), { Position = ... }):Play()
    .
  • Animate
    UIScale.Scale
    for pop effects rather than
    Size
    (keeps layout stable).
  • CanvasGroup
    fades a whole subtree (
    GroupTransparency
    ) but renders to a texture: use it for fading panels, not for large always-visible UI (memory/quality cost).
  • Drag-and-drop:
    UIDragDetector
    (the deprecated
    GuiObject.Draggable
    no longer works for new work).
  • 在客户端执行 Tween:
    TweenService:Create(frame, TweenInfo.new(0.2, Enum.EasingStyle.Quad), { Position = ... }):Play()
    。
  • 为弹出效果设置
    UIScale.Scale
    动画,而不是设置
    Size
    (这样可保持布局稳定)。
  • CanvasGroup
    可以淡入淡出整个子树(
    GroupTransparency
    ),但会先渲染为 texture:仅将其 用于需要淡入淡出的面板,不要用于大型且始终可见的 UI(会带来内存和画质成本)。
  • 拖放:使用
    UIDragDetector
    (已弃用的
    GuiObject.Draggable
    不再用于新项目)。

World-space UI

世界空间 UI

  • BillboardGui
    (faces camera: names, health bars) — set
    MaxDistance
    ,
    AlwaysOnTop
    sparingly, use
    Size
    in Scale for distance scaling;
    SurfaceGui
    for screens/signs on parts. Prefer
    Adornee
    + keep them in
    PlayerGui
    for per-player content. They stop rendering when their part streams out.
  • ProximityPrompt
    gives cross-platform interaction UI for free (validate on the server!).
  • BillboardGui
    (朝向摄像机:名称、血条)——设置
    MaxDistance
    ,谨慎使用
    AlwaysOnTop
    ,使用 Scale 设置
    Size
    以实现距离缩放;
    SurfaceGui
    用于部件上的屏幕或标牌。优先使用
    Adornee
    ,并将其保留在
    PlayerGui
    中,以支持每位玩家独立的内容。当关联 Part stream out 后, 它们会停止渲染。
  • ProximityPrompt
    可直接提供跨平台交互 UI(务必在服务端验证!)。

Frameworks

框架

For more than a few screens, a declarative framework keeps state and UI in sync:
  • React (
    jsdotlua/react
    +
    react-roblox
    ) — components + hooks, familiar to web devs, scales to big apps.
  • Fusion — reactive state objects and declarative instance creation.
  • Vide — small, fast reactive library. Match whatever the project already uses. Keep game state in controllers; UI only renders it and emits user intents.
当界面不止几个屏幕时,声明式 framework 可让状态与 UI 保持同步:
  • React(
    jsdotlua/react
    +
    react-roblox
    )——components + hooks,web 开发者熟悉, 可扩展到大型应用。
  • Fusion——响应式状态对象和声明式实例创建。
  • Vide——轻量、快速的响应式库。
与项目当前使用的方案保持一致。将游戏状态保留在 controllers 中;UI 只负责渲染状态并发出用户意图。

Performance

性能

  • Avoid updating text/properties every frame when values haven't changed.
  • Hide closed menus with
    Visible = false
    (or
    Enabled = false
    on the ScreenGui) instead of destroying/recreating them repeatedly; build large lists lazily or virtualize them.
  • Too many
    UIGradient
    /
    CanvasGroup
    /
    UIStroke
    on dynamic UI costs frame time; check the MicroProfiler.
  • 当值未发生变化时,避免每帧更新文本或属性。
  • 使用
    Visible = false
    (或在
    ScreenGui
    上使用
    Enabled = false
    )隐藏已关闭的菜单,而不是反复销毁和重新创建; 对大型列表进行延迟构建或虚拟化。
  • 动态 UI 上过多使用
    UIGradient
    /
    CanvasGroup
    /
    UIStroke
    会消耗帧时间;使用 MicroProfiler 检查。

Related skills

相关 skills

roblox-input
(actions, gamepad),
roblox-text-chat
(filtering),
roblox-monetization
(shops),
roblox-luau
,
roblox-performance
.
roblox-input
(操作、gamepad)、
roblox-text-chat
(过滤)、
roblox-monetization
(商店)、
roblox-luau
、
roblox-performance
。