mcpField
R
roblox-ui

roblox-ui

github.com/gamedev-skills设计与 UI5.4k4.5k 次安装1 天前更新
代码仓库

关于 roblox-ui

面向使用 Roblox Instances 和平台 API 的开发者的 UI 实现技能,强调可编辑层级、响应式布局、输入与焦点处理,以及跨设备测试。

主要功能

  1. 01ScreenGui 层级与生命周期
  2. 02响应式布局与约束
  3. 03安全区域与设备遮挡处理
  4. 04触控、手柄和键盘输入
  5. 05兼顾动态偏好的状态过渡
  6. 06跨设备 UI 验证

适用场景

  1. 01替换脆弱的像素定位界面
  2. 02构建背包等响应式屏幕
  3. 03修复焦点与手柄导航问题
  4. 04检查不同视口和设备上的 UI

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/gamedev-skills/awesome-gamedev-agent-skills --skill roblox-ui

安装后在 Claude Code 中输入/roblox-ui确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

agents/
openai.yaml
assets/
inventory-quality-test.model.json
inventory-quality-test.project.json
references/
input-navigation.md
responsive-layout.md

详细介绍

Roblox UI

构建有明确设计、可编辑的 Roblox UI,保留体验的视觉语言,并适配所有受支持的设备。面向 Roblox 持续更新的平台 API。搭配 game-ui-ux 使用,获取与引擎无关的信息架构和 UX;本技能负责 Roblox Instances 和 API。

适用场景

  • 用于编写 ScreenGui 界面、Roblox 布局/约束 API、UI 生命周期、输入、焦点、动画、性能或响应式/设备适配。
  • 用于替换脆弱的像素布局、运行时创建的 Instance 乱象、仅支持鼠标的菜单或通用的生成式样式,构建易维护的层级结构。

不适用场景: 通用 UX 流程和无障碍原则应交由 game-ui-ux;原始游戏玩法操作映射应交由 input-systems;服务端信任应交由 roblox-networking。

工作流

  1. 先检查,再设计。 在 Explorer 中盘点现有的 ScreenGui、UI 模块、字体、颜色、图标系列、间距、圆角、描边、动画时长、命名和可复用组件。截取两种视口下具有代表性的屏幕截图。延续现有设计语言。
  2. 明确所有权和生命周期。 StarterGui 是编写的模板;Roblox 会将其克隆到每位玩家的 PlayerGui 中。确定每个 ScreenGui 是否应通过 ResetOnSpawn = false 在重生后保留;绝不要保留已销毁克隆的过期引用。
  3. 编写清晰易读的层级结构。 优先使用有意义、可编辑的 Instances 和小型行为模块。正常的屏幕结构应便于在 Explorer 中理解;仅在确实需要数据驱动的重复内容时使用程序化生成,不要用它构建整个外壳。
  4. 构建响应式结构。 结合使用 UDim2 缩放定位与有界偏移、正确的 AnchorPoint、布局、内边距、内容尺寸和约束。明确选择窄屏/宽屏布局,而不是不断缩小桌面面板,直到勉强适配。
  5. 处理平台遮挡。 将可交互 UI 放在 CoreUISafeInsets 内(这是推荐的 ScreenGui.ScreenInsets 默认值),并考虑触控控制区域以及电视观看距离/过扫描。
  6. 连接状态与输入。 根据精简的视图状态进行渲染,并在事件发生时更新。对 GuiButton 使用 Activated,明确设置选中状态,并确保手柄导航可达。只有在屏幕拥有非控件操作期间,才使用 ContextActionService 绑定这些操作。
  7. 适度润色。 实现悬停、按下、选中和禁用状态。为状态变化添加动画,而非装饰;遵守 GuiService.ReducedMotionEnabled,并在屏幕关闭或被替换时清理补间和连接。
  8. 验证实际界面。 使用 Device Emulator 和 Controller Emulator。测试桌面、窄屏竖屏、移动设备横屏、类平板设备以及主机/手柄;然后重生。记录裁切、重叠、文本、滚动、安全区域、焦点路径、触控目标和生命周期测试结果。

生产结构

StarterGui
└── InventoryGui (ScreenGui; ResetOnSpawn = false)
    ├── Root (Frame)
    │   ├── Header
    │   ├── Content
    │   │   ├── CategoryList
    │   │   ├── ItemGrid (ScrollingFrame)
    │   │   └── DetailsPanel
    │   └── Footer
    └── InventoryController (LocalScript)
ReplicatedStorage
└── UI
    ├── Components
    └── Theme

名称应描述用途,而非颜色或临时位置。将重复的项目单元格保留为模板或组件,同时确保在 Explorer 中能看到编写好的外壳。

模式

适应内容和视口变化的布局
-- Authored properties on ItemGrid (ScrollingFrame):
--   AutomaticCanvasSize = Enum.AutomaticSize.Y
--   CanvasSize = UDim2.fromOffset(0, 0)
-- Children: UIPadding + UIGridLayout
local grid = itemGrid.UIGridLayout
local projectBreakpoint = 700 -- derive from where this composition stops being usable

local function applyComposition()
    local narrow = root.AbsoluteSize.X < projectBreakpoint
    categoryList.UIListLayout.FillDirection = if narrow
        then Enum.FillDirection.Horizontal
        else Enum.FillDirection.Vertical
    categoryList.Size = if narrow
        then UDim2.new(1, 0, 0, 40)
        else UDim2.new(0, 148, 1, 0)
    itemGrid.Position = if narrow then UDim2.fromOffset(0, 52) else UDim2.fromOffset(164, 0)
    itemGrid.Size = if narrow
        then UDim2.new(1, 0, 1, -52)
        else UDim2.new(0.58, -164, 1, 0)
    detailsPanel.Visible = not narrow -- open details as a separate narrow-screen state

    local width = itemGrid.AbsoluteSize.X
    local columns = if width < 520 then 2 elseif width < 820 then 3 else 4
    local gap = 12
    local usable = width - itemGrid.UIPadding.PaddingLeft.Offset
        - itemGrid.UIPadding.PaddingRight.Offset - gap * (columns - 1)
    grid.CellSize = UDim2.fromOffset(math.floor(usable / columns), 112)
    grid.CellPadding = UDim2.fromOffset(gap, gap)
end

root:GetPropertyChangedSignal("AbsoluteSize"):Connect(applyComposition)
applyComposition()

一维排列使用 UIListLayout,统一单元格使用 UIGridLayout,只有在确实需要按行/列对齐时才使用 UITableLayout。AutomaticSize 可适应内容尺寸;AutomaticCanvasSize 可适应滚动内容尺寸。使用 UISizeConstraint、UIAspectRatioConstraint 或 UITextSizeConstraint 限制极端尺寸,而不要依赖单一的全局 UIScale 猜测值。

一条激活路径和明确的手柄入口
local GuiService = game:GetService("GuiService")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")

local function openInventory()
    root.Visible = true
    task.spawn(function()
        RunService.RenderStepped:Wait() -- selection must be rendered and selectable
        if root.Visible and (UserInputService.GamepadEnabled
            or (UserInputService.KeyboardEnabled and not UserInputService.TouchEnabled)) then
            GuiService.SelectedObject = firstItemButton
        end
    end)
end

local function closeInventory()
    GuiService.SelectedObject = nil
    root.Visible = false
end

firstItemButton.Activated:Connect(function()
    selectItem(firstItemButton:GetAttribute("ItemId"))
end)

优先使用 Activated,而不是分别处理鼠标和触摸事件。自动导航存在歧义时,设置 NextSelectionUp/Down/Left/Right,尤其是网格、侧边栏和模态框附近。模态框必须将焦点限制在自身内部,并在关闭时恢复到合理的选中项。

对于跨设备操作绑定,Input Action System(InputContext/InputAction/InputBinding)是现代的编辑时层;参见 references/input-navigation.md。

结合实际界面检查 Roblox 的默认选中装饰。如果它过于醒目,请指定项目自有的 SelectionImageObject 或选中态样式;应保持其可见、有效且克制,而不是禁用焦点反馈。

无多余动画的状态转换
local TweenService = game:GetService("TweenService")
local GuiService = game:GetService("GuiService")
local fade = TweenInfo.new(0.14, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)

local function setPanelVisible(visible: boolean)
    panel.Visible = true -- panel is a CanvasGroup
    if GuiService.ReducedMotionEnabled then
        panel.GroupTransparency = if visible then 0 else 1
    else
        TweenService:Create(panel, fade, {
            GroupTransparency = if visible then 0 else 1,
        }):Play()
    end
    if not visible then
        task.delay(fade.Time, function()
            if panel.GroupTransparency == 1 then panel.Visible = false end
        end)
    end
end

对面板或状态边界动画一次即可。不要让每个子元素都单独弹跳。

视觉质量门槛

  • 先通过大小、字重、对比度、分组和留白建立层次,再添加装饰。使用小范围的间距刻度,并按其对齐。
  • 保持游戏的字体、配色、图标、圆角和描边风格。如果没有现成规范,就定义一个精简的设计令牌模块;不要为每个组件临时发挥。
  • 只在材质或形状需要时使用圆角,不要给每个嵌套的 Frame 都加圆角。避免卡片层层嵌套、到处使用胶囊形、随意添加渐变/辉光/阴影、霓虹描边、过度透明/模糊、过大的标题、无意义的图标和巨大的空白面板。
  • 重要程度不同的按钮不应看起来完全相同。仅按需定义主要、次要、弱强调、危险、选中、按下、悬停和禁用样式。
  • 动画用于传达打开/关闭、焦点、确认或空间关系。动画应简短、可中断且细微;避免持续运动和装饰性的补间动画链。
  • 在触屏设备上,为默认的移动/跳跃区域留出空间。移动或重新编排与其重叠的底部操作,并在键盘/手柄输入未启用时隐藏相应提示。

常见问题

症状可能原因解决方法
重生后 UI 消失或重复ResetOnSpawn 策略不正确或克隆已过期选择合适的策略;从 PlayerGui 重新获取;清理旧绑定
手机布局被裁切将桌面端偏移/全局缩放用作布局添加窄屏布局、布局对象和边界,并使用 Device Emulator 检查
内容被顶栏/缺口遮挡忽略了内边距,或设置了 ScreenInsets = None交互式 UI 使用 CoreUISafeInsets;检查有意的延伸区域
滚动提前结束CanvasSize 固定使用 AutomaticCanvasSize 或布局的 AbsoluteContentSize
控制器卡住缺少入口选中项或相邻关系图错误设置初始 SelectedObject;定义并测试焦点路径/模态框焦点限制
UI 看起来像自动生成的用装饰取代了层次结构移除特效;调整对齐、减少嵌套、修正密度和组件职责
连接/补间数量不断增加屏幕重新绑定但未清理按屏幕生命周期管理连接;在销毁时断开连接/取消动画

资源

  • 阅读 references/responsive-layout.md,了解布局决策、内边距策略、密度以及必需的视口矩阵。
  • 在实现手柄/触摸焦点、模态框行为、操作绑定或动画偏好时,阅读 references/input-navigation.md。
  • 使用 Rojo 构建 assets/inventory-quality-test.project.json(它映射相邻的 JSON 模型),以生成可编辑的 Instance 测试夹具,用于视觉/布局审查;它是测试基准,不是可上线游戏的样式模板。

相关技能

  • game-ui-ux — 信息层级、屏幕流程、无障碍设计和 UX 验证。
  • input-systems — 游戏操作映射和设备切换。
  • roblox-networking — 由 UI 发起的服务器权威请求。
  • roblox-studio-workflow — 以 Explorer 为先的编辑方式和 Studio 验证。

主要参考资料

  • Roblox Creator Hub:https://create.roblox.com/docs/ui/on-screen-containers
  • Roblox Creator Hub:https://create.roblox.com/docs/ui/position-and-size
  • Roblox Creator Hub:https://create.roblox.com/docs/ui/size-modifiers
  • Roblox Creator Hub:https://create.roblox.com/docs/studio/testing-modes

评论

支持 Markdown