From ad05bc1bb228bc9273ef31280c4cddae74d3ae7e Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Feb 2026 22:01:30 +0000 Subject: [PATCH 001/186] Add React Luau dependency Signed-off-by: GitHub --- wally.lock | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++- wally.toml | 2 ++ 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/wally.lock b/wally.lock index fbe98925..6c2c7f94 100644 --- a/wally.lock +++ b/wally.lock @@ -7,7 +7,92 @@ name = "1foreverhd/topbarplus" version = "3.4.0" dependencies = [] +[[package]] +name = "jsdotlua/boolean" +version = "1.2.7" +dependencies = [["number", "jsdotlua/number@1.2.7"]] + +[[package]] +name = "jsdotlua/collections" +version = "1.2.7" +dependencies = [["es7-types", "jsdotlua/es7-types@1.2.7"], ["instance-of", "jsdotlua/instance-of@1.2.7"]] + +[[package]] +name = "jsdotlua/console" +version = "1.2.7" +dependencies = [["collections", "jsdotlua/collections@1.2.7"]] + +[[package]] +name = "jsdotlua/es7-types" +version = "1.2.7" +dependencies = [] + +[[package]] +name = "jsdotlua/instance-of" +version = "1.2.7" +dependencies = [] + +[[package]] +name = "jsdotlua/luau-polyfill" +version = "1.2.7" +dependencies = [["boolean", "jsdotlua/boolean@1.2.7"], ["collections", "jsdotlua/collections@1.2.7"], ["console", "jsdotlua/console@1.2.7"], ["es7-types", "jsdotlua/es7-types@1.2.7"], ["instance-of", "jsdotlua/instance-of@1.2.7"], ["math", "jsdotlua/math@1.2.7"], ["number", "jsdotlua/number@1.2.7"], ["string", "jsdotlua/string@1.2.7"], ["symbol-luau", "jsdotlua/symbol-luau@1.0.1"], ["timers", "jsdotlua/timers@1.2.7"]] + +[[package]] +name = "jsdotlua/math" +version = "1.2.7" +dependencies = [] + +[[package]] +name = "jsdotlua/number" +version = "1.2.7" +dependencies = [] + +[[package]] +name = "jsdotlua/promise" +version = "3.5.2" +dependencies = [] + +[[package]] +name = "jsdotlua/react" +version = "17.2.1" +dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["shared", "jsdotlua/shared@17.2.1"]] + +[[package]] +name = "jsdotlua/react-reconciler" +version = "17.2.1" +dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["promise", "jsdotlua/promise@3.5.2"], ["react", "jsdotlua/react@17.2.1"], ["scheduler", "jsdotlua/scheduler@17.2.1"], ["shared", "jsdotlua/shared@17.2.1"]] + +[[package]] +name = "jsdotlua/react-roblox" +version = "17.2.1" +dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["react", "jsdotlua/react@17.2.1"], ["react-reconciler", "jsdotlua/react-reconciler@17.2.1"], ["scheduler", "jsdotlua/scheduler@17.2.1"], ["shared", "jsdotlua/shared@17.2.1"]] + +[[package]] +name = "jsdotlua/scheduler" +version = "17.2.1" +dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["shared", "jsdotlua/shared@17.2.1"]] + +[[package]] +name = "jsdotlua/shared" +version = "17.2.1" +dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"]] + +[[package]] +name = "jsdotlua/string" +version = "1.2.7" +dependencies = [["es7-types", "jsdotlua/es7-types@1.2.7"], ["number", "jsdotlua/number@1.2.7"]] + +[[package]] +name = "jsdotlua/symbol-luau" +version = "1.0.1" +dependencies = [] + +[[package]] +name = "jsdotlua/timers" +version = "1.2.7" +dependencies = [["collections", "jsdotlua/collections@1.2.7"]] + [[package]] name = "ryanlua/satchel" version = "1.4.1" -dependencies = [["topbarplus", "1foreverhd/topbarplus@3.4.0"]] +dependencies = [["react", "jsdotlua/react@17.2.1"], ["react-roblox", "jsdotlua/react-roblox@17.2.1"], ["topbarplus", "1foreverhd/topbarplus@3.4.0"]] diff --git a/wally.toml b/wally.toml index e17d53cb..4772f9dd 100644 --- a/wally.toml +++ b/wally.toml @@ -12,4 +12,6 @@ exclude = ["**"] include = ["src", "src/**", "wally.toml", "wally.lock", "default.project.json", "LICENSE", "README.md"] [dependencies] +react = "jsdotlua/react@17.2.1" +react-roblox = "jsdotlua/react-roblox@17.2.1" topbarplus = "1foreverhd/topbarplus@3.4.0" From cdd65fb0713dcafcb8d8fec03fc797ed19164ed1 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Feb 2026 22:42:22 +0000 Subject: [PATCH 002/186] Add example from Flipbook Signed-off-by: GitHub --- src/Components/Button.luau | 19 +++++++++++++++++++ src/Components/Button.story.luau | 23 +++++++++++++++++++++++ src/Components/Satchel.storybook.luau | 13 +++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 src/Components/Button.luau create mode 100644 src/Components/Button.story.luau create mode 100644 src/Components/Satchel.storybook.luau diff --git a/src/Components/Button.luau b/src/Components/Button.luau new file mode 100644 index 00000000..0dd9dc75 --- /dev/null +++ b/src/Components/Button.luau @@ -0,0 +1,19 @@ +local React = require(script.Parent.Parent.Parent.react) + +local function ReactButton(props: { + text: string, + onActivated: () -> (), +}) + return React.createElement("TextButton", { + Text = props.text, + TextSize = 16, + Font = Enum.Font.BuilderSansExtraBold, + TextColor3 = Color3.fromRGB(50, 50, 50), + BackgroundColor3 = Color3.fromRGB(255, 255, 255), + BorderSizePixel = 0, + Size = UDim2.fromOffset(200, 40), + [React.Event.Activated] = props.onActivated, + }) +end + +return ReactButton \ No newline at end of file diff --git a/src/Components/Button.story.luau b/src/Components/Button.story.luau new file mode 100644 index 00000000..1b4565ce --- /dev/null +++ b/src/Components/Button.story.luau @@ -0,0 +1,23 @@ +local React = require(script.Parent.Parent.Parent.react) +local ReactRoblox = require(script.Parent.Parent.Parent["react-roblox"]) + +return { + story = function() + return React.createElement("TextButton", { + Text = "Click Me", + TextSize = 16, + Font = Enum.Font.BuilderSansExtraBold, + TextColor3 = Color3.fromRGB(50, 50, 50), + BackgroundColor3 = Color3.fromRGB(255, 255, 255), + BorderSizePixel = 0, + Size = UDim2.fromOffset(200, 40), + [React.Event.Activated] = function() + print("clicked") + end, + }) + end, + packages = { + React = React, + ReactRoblox = ReactRoblox, + }, +} \ No newline at end of file diff --git a/src/Components/Satchel.storybook.luau b/src/Components/Satchel.storybook.luau new file mode 100644 index 00000000..3aa95e33 --- /dev/null +++ b/src/Components/Satchel.storybook.luau @@ -0,0 +1,13 @@ +local React = require(script.Parent.Parent.Parent.react) +local ReactRoblox = require(script.Parent.Parent.Parent["react-roblox"]) + +return { + name = "Satchel", + storyRoots = { + script.Parent, + }, + packages = { + React = React, + ReactRoblox = ReactRoblox, + }, +} \ No newline at end of file From b11321cae4a9683114e504b47f94ea819c1d2109 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Feb 2026 23:00:49 +0000 Subject: [PATCH 003/186] Add basic tooltip Signed-off-by: GitHub --- src/Components/ToolTip.luau | 17 +++++++++++++++++ src/Components/ToolTip.story.luau | 20 ++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 src/Components/ToolTip.luau create mode 100644 src/Components/ToolTip.story.luau diff --git a/src/Components/ToolTip.luau b/src/Components/ToolTip.luau new file mode 100644 index 00000000..f400c597 --- /dev/null +++ b/src/Components/ToolTip.luau @@ -0,0 +1,17 @@ +local React = require(script.Parent.Parent.Parent.react) + +local function ToolTip(props: { + text: string?, +}) + -- Hide tooltip if there is no text + if not props.text or props.text == "" then + return nil + end + + return React.createElement("TextLabel", { + Text = props.text, + [React.Tag] = "ToolTip", + }) +end + +return ToolTip diff --git a/src/Components/ToolTip.story.luau b/src/Components/ToolTip.story.luau new file mode 100644 index 00000000..bef61e0e --- /dev/null +++ b/src/Components/ToolTip.story.luau @@ -0,0 +1,20 @@ +local React = require(script.Parent.Parent.Parent.react) + +local ToolTip = require(script.Parent.ToolTip) + +local controls = { + text = "I'm a tooltip!", +} + +type Props = { + controls: typeof(controls), +} + +return { + controls = controls, + story = function(props: Props) + return React.createElement(ToolTip, { + text = props.controls.text, + }) + end, +} From 32cf04bab15f7bc07f33583bc7c7abc927cbc784 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Feb 2026 23:07:50 +0000 Subject: [PATCH 004/186] Add style sheets Signed-off-by: GitHub --- src/Components/ToolTip.luau | 3 +- src/Components/ToolTip.story.luau | 4 + src/StyleSheets.rbxmx | 1214 +++++++++++++++++++++++++++++ 3 files changed, 1220 insertions(+), 1 deletion(-) create mode 100644 src/StyleSheets.rbxmx diff --git a/src/Components/ToolTip.luau b/src/Components/ToolTip.luau index f400c597..33b7dd70 100644 --- a/src/Components/ToolTip.luau +++ b/src/Components/ToolTip.luau @@ -2,6 +2,7 @@ local React = require(script.Parent.Parent.Parent.react) local function ToolTip(props: { text: string?, + children: any?, }) -- Hide tooltip if there is no text if not props.text or props.text == "" then @@ -11,7 +12,7 @@ local function ToolTip(props: { return React.createElement("TextLabel", { Text = props.text, [React.Tag] = "ToolTip", - }) + }, props.children) end return ToolTip diff --git a/src/Components/ToolTip.story.luau b/src/Components/ToolTip.story.luau index bef61e0e..4222e64c 100644 --- a/src/Components/ToolTip.story.luau +++ b/src/Components/ToolTip.story.luau @@ -15,6 +15,10 @@ return { story = function(props: Props) return React.createElement(ToolTip, { text = props.controls.text, + }, { + StyleLink = React.createElement("StyleLink", { + StyleSheet = script.Parent.Parent.StyleSheets.SatchelStyleSheet, + }), }) end, } diff --git a/src/StyleSheets.rbxmx b/src/StyleSheets.rbxmx new file mode 100644 index 00000000..6826b54e --- /dev/null +++ b/src/StyleSheets.rbxmx @@ -0,0 +1,1214 @@ + + true + null + nil + + + + 0 + false + StyleSheets + -1 + + + + + + 0 + false + SatchelStyleSheet + -1 + + + + + 12 + AAAAAA== + Frame + + 0 + false + Frame + -1 + + + + + 2 + + .Hint + + 0 + false + .Hint + -1 + + + + + 3 + + >TextLabel + + 0 + false + >TextLabel + -1 + + + + + + 4 + + >ImageLabel + + 0 + false + >ImageLabel + -1 + + + + + 1 + AAAAAA== + ::UIAspectRatioConstraint + + 0 + false + ::UIAspectRatioConstraint + -1 + + + + + + + + + 11 + AAAAAA== + ScrollingFrame + + 0 + false + ScrollingFrame + -1 + + + + + + 10 + AAAAAA== + TextLabel + + 0 + false + TextLabel + -1 + + + + + 9 + + .ToolTip + + 0 + false + .ToolTip + -1 + + + + + 1 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz + ::UICorner + + 0 + false + ::UICorner + -1 + + + + + + 2 + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + + + + + + 8 + AAAAAA== + TextButton + + 0 + false + TextButton + -1 + + + + + 2 + + .Slot + + 0 + false + .Slot + -1 + + + + + 10 + AAAAAA== + .Equipped + + 0 + false + .Equipped + -1 + + + + + 1 + + ::UIStroke + + 0 + false + ::UIStroke + -1 + + + + + + + 8 + AAAAAA== + :Hover + + 0 + false + :Hover + -1 + + + + + 1 + AQAAAAcAAABWaXNpYmxlAwE= + >.ToolTip + + 0 + false + >.ToolTip + -1 + + + + + + + 7 + + >ImageLabel + + 0 + false + >ImageLabel + -1 + + + + + 1 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== + ::UICorner + + 0 + false + ::UICorner + -1 + + + + + + + 6 + + ::UITextSizeConstraint + + 0 + false + ::UITextSizeConstraint + -1 + + + + + + 5 + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + + + + 4 + AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= + >TextLabel + + 0 + false + >TextLabel + -1 + + + + + 9 + AQAAAAcAAABWaXNpYmxlAwA= + .ToolTip + + 0 + false + .ToolTip + -1 + + + + + + 1 + + .SlotNumber + + 0 + false + .SlotNumber + -1 + + + + + + + 1 + AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz + ::UICorner + + 0 + false + ::UICorner + -1 + + + + + + 11 + + .Unlocked + + 0 + false + .Unlocked + -1 + + + + + 9 + AAAAAA== + :Press + + 0 + false + :Press + -1 + + + + + 1 + + ::UIStroke + + 0 + false + ::UIStroke + -1 + + + + + + + + 9 + AAAAAA== + :Press + + 0 + false + :Press + -1 + + + + + 2 + AQAAAAcAAABWaXNpYmxlAwE= + >.ToolTip + + 0 + false + >.ToolTip + -1 + + + + + + + + + 7 + AAAAAA== + TextBox + + 0 + false + TextBox + -1 + + + + + 2 + + .SearchBar + + 0 + false + .SearchBar + -1 + + + + + 1 + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + + + + 3 + + >ImageButton + + 0 + false + >ImageButton + -1 + + + + + 1 + AAAAAA== + ::UIAspectRatioConstraint + + 0 + false + ::UIAspectRatioConstraint + -1 + + + + + + + + + 6 + AAAAAA== + ImageButton + + 0 + false + ImageButton + -1 + + + + + + 5 + AAAAAA== + ImageLabel + + 0 + false + ImageLabel + -1 + + + + + 1 + + .HintSlot + + 0 + false + .HintSlot + -1 + + + + + 1 + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== + ::UIAspectRatioConstraint + + 0 + false + ::UIAspectRatioConstraint + -1 + + + + + + + + 1 + RBX551A91E21149401EBB451F11ACC4116A + + 0 + false + Derive from BaseStyleSheet + -1 + + + + + + 0 + RBX1A83A5F422C64C4A839C0EE03B906222 + + 0 + false + Derive from DefaultTheme + -1 + + + + + + 5 + + .Hotbar + + 0 + false + .Hotbar + -1 + + + + + 1 + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + + + + + 3 + + .Container,.SearchBar + + 0 + false + .Container,.SearchBar + -1 + + + + + 2 + + ::UIStroke + + 0 + false + ::UIStroke + -1 + + + + + + 1 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= + ::UICorner + + 0 + false + ::UICorner + -1 + + + + + + 2 + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + + + + + 3 + + .Surface,.Hints,.Inventory + + 0 + false + .Surface,.Hints,.Inventory + -1 + + + + + 1 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz + ::UICorner + + 0 + false + ::UICorner + -1 + + + + + + 2 + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + + + + + 0 + null + + 0 + false + Derive from StyleSheet + -1 + + + + + + 6 + + .Hints + + 0 + false + .Hints + -1 + + + + + 1 + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + + + + + 7 + AQAAAAsAAABMYXlvdXRPcmRlcgYAAAAAAAAAAA== + .Inventory + + 0 + false + .Inventory + -1 + + + + + 1 + AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + + + + 1 + + >ScrollingFrame + + 0 + false + >ScrollingFrame + -1 + + + + + 2 + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + + + + + + 8 + + .Backpack + + 0 + false + .Backpack + -1 + + + + + 1 + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + + + + 2 + AQAAAA0AAABQYWRkaW5nQm90dG9tCQAAAAAFAAAA + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + + + + + + + 0 + false + BaseTokens + -1 + + + + + 0 + RBX3FCD09B5CC5E49539C0DDCA0030578EE + + 0 + false + Derive from DesignTokens + -1 + + + + + + + + 0 + false + DesignTokens + -1 + + + + + + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= + 0 + false + DefaultTheme + -1 + + + + + 0 + RBX5386E31C9C0C4A45B50A17CA8B9D2965 + + 0 + false + Derive from BaseTokens + -1 + + + + + + + + 0 + false + LegacyTheme + -1 + + + + + 0 + RBX5386E31C9C0C4A45B50A17CA8B9D2965 + + 0 + false + Derive from BaseTokens + -1 + + + + + + + + 0 + false + BaseStyleSheet + -1 + + + + + 0 + + Frame + + 0 + false + Frame + -1 + + + + + + 1 + + ScrollingFrame + + 0 + false + ScrollingFrame + -1 + + + + + + 2 + + TextLabel + + 0 + false + TextLabel + -1 + + + + + + 3 + + TextButton + + 0 + false + TextButton + -1 + + + + + + 4 + + TextBox + + 0 + false + TextBox + -1 + + + + + + 5 + + ImageButton + + 0 + false + ImageButton + -1 + + + + + + 6 + + ImageLabel + + 0 + false + ImageLabel + -1 + + + + + + 7 + + ViewportFrame + + 0 + false + ViewportFrame + -1 + + + + + + 8 + + VideoFrame + + 0 + false + VideoFrame + -1 + + + + + + 9 + + CanvasGroup + + 0 + false + CanvasGroup + -1 + + + + + + 10 + AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= + UIListLayout + + 0 + false + UIListLayout + -1 + + + + + + 11 + AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= + UIGridLayout + + 0 + false + UIGridLayout + -1 + + + + + + 12 + AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= + UIPageLayout + + 0 + false + UIPageLayout + -1 + + + + + + 13 + AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= + UITableLayout + + 0 + false + UITableLayout + -1 + + + + + + \ No newline at end of file From 2c1b4d683616193a6390a4396a37c09717cc18fb Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Feb 2026 23:15:48 +0000 Subject: [PATCH 005/186] Add tooltip summary and fix capitalization Signed-off-by: GitHub --- src/Components/{ToolTip.luau => Tooltip.luau} | 6 +++--- src/Components/{ToolTip.story.luau => Tooltip.story.luau} | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) rename src/Components/{ToolTip.luau => Tooltip.luau} (79%) rename src/Components/{ToolTip.story.luau => Tooltip.story.luau} (73%) diff --git a/src/Components/ToolTip.luau b/src/Components/Tooltip.luau similarity index 79% rename from src/Components/ToolTip.luau rename to src/Components/Tooltip.luau index 33b7dd70..75564878 100644 --- a/src/Components/ToolTip.luau +++ b/src/Components/Tooltip.luau @@ -1,6 +1,6 @@ local React = require(script.Parent.Parent.Parent.react) -local function ToolTip(props: { +local function Tooltip(props: { text: string?, children: any?, }) @@ -11,8 +11,8 @@ local function ToolTip(props: { return React.createElement("TextLabel", { Text = props.text, - [React.Tag] = "ToolTip", + [React.Tag] = "Tooltip", }, props.children) end -return ToolTip +return Tooltip diff --git a/src/Components/ToolTip.story.luau b/src/Components/Tooltip.story.luau similarity index 73% rename from src/Components/ToolTip.story.luau rename to src/Components/Tooltip.story.luau index 4222e64c..9e0076fc 100644 --- a/src/Components/ToolTip.story.luau +++ b/src/Components/Tooltip.story.luau @@ -1,6 +1,6 @@ local React = require(script.Parent.Parent.Parent.react) -local ToolTip = require(script.Parent.ToolTip) +local Tooltip = require(script.Parent.Tooltip) local controls = { text = "I'm a tooltip!", @@ -11,9 +11,10 @@ type Props = { } return { + summary = "Message displayed when hovering over a slot", controls = controls, story = function(props: Props) - return React.createElement(ToolTip, { + return React.createElement(Tooltip, { text = props.controls.text, }, { StyleLink = React.createElement("StyleLink", { From 3ea5c609d5cc263b6e60356f13798f394992feea Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Feb 2026 23:24:48 +0000 Subject: [PATCH 006/186] Fix stylesheet Signed-off-by: GitHub --- src/StyleSheets.rbxmx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/StyleSheets.rbxmx b/src/StyleSheets.rbxmx index 6826b54e..59c840ae 100644 --- a/src/StyleSheets.rbxmx +++ b/src/StyleSheets.rbxmx @@ -126,11 +126,11 @@ bmRUcmFucGFyZW5jeQgAAABGb250RmFjZQIQAAAAJFRvb2xUaXBGb250RmFjZQgAAABQb3Np dGlvbgoAAAA/AAAAAAAAAAD2////BAAAAFNpemUKAAAAAAAAAAAAAAAAAAAAAAoAAABUZXh0 Q29sb3IzAhEAAAAkVG9vbFRpcFRleHRDb2xvcggAAABUZXh0U2l6ZQIQAAAAJFRvb2xUaXBU ZXh0U2l6ZQ==]]> - .ToolTip + .Tooltip 0 false - .ToolTip + .Tooltip -1 @@ -239,11 +239,11 @@ b2luTW9kZQAAAAAJAAAAVGhpY2tuZXNzAhkAAAAkU2xvdEVxdWlwU3Ryb2tlVGhpY2tuZXNz 1 AQAAAAcAAABWaXNpYmxlAwE= - >.ToolTip + >.Tooltip 0 false - >.ToolTip + >.Tooltip -1 @@ -321,11 +321,11 @@ YWRkaW5nVG9wAgwAAAAkU2xvdFBhZGRpbmc=]]> 9 AQAAAAcAAABWaXNpYmxlAwA= - .ToolTip + .Tooltip 0 false - .ToolTip + .Tooltip -1 @@ -421,11 +421,11 @@ b3ICFQAAACRTbG90UHJlc3NTdHJva2VDb2xvcgkAAABUaGlja25lc3MGAAAAAAAAAEA=]]> 2 AQAAAAcAAABWaXNpYmxlAwE= - >.ToolTip + >.Tooltip 0 false - >.ToolTip + >.Tooltip -1 From c954bad0707146ea7b58d2f73f67a4767a3d68f5 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Feb 2026 23:24:54 +0000 Subject: [PATCH 007/186] Export types Signed-off-by: GitHub --- src/Components/Tooltip.luau | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Components/Tooltip.luau b/src/Components/Tooltip.luau index 75564878..d190584d 100644 --- a/src/Components/Tooltip.luau +++ b/src/Components/Tooltip.luau @@ -1,9 +1,11 @@ local React = require(script.Parent.Parent.Parent.react) -local function Tooltip(props: { +export type Props = { text: string?, children: any?, -}) +} + +local function Tooltip(props: Props) -- Hide tooltip if there is no text if not props.text or props.text == "" then return nil From 1e2818a67f11ad03cac028ae5e01790b5f469334 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Feb 2026 23:42:05 +0000 Subject: [PATCH 008/186] Remove button component Signed-off-by: GitHub --- src/Components/Button.luau | 19 ------------------- src/Components/Button.story.luau | 23 ----------------------- 2 files changed, 42 deletions(-) delete mode 100644 src/Components/Button.luau delete mode 100644 src/Components/Button.story.luau diff --git a/src/Components/Button.luau b/src/Components/Button.luau deleted file mode 100644 index 0dd9dc75..00000000 --- a/src/Components/Button.luau +++ /dev/null @@ -1,19 +0,0 @@ -local React = require(script.Parent.Parent.Parent.react) - -local function ReactButton(props: { - text: string, - onActivated: () -> (), -}) - return React.createElement("TextButton", { - Text = props.text, - TextSize = 16, - Font = Enum.Font.BuilderSansExtraBold, - TextColor3 = Color3.fromRGB(50, 50, 50), - BackgroundColor3 = Color3.fromRGB(255, 255, 255), - BorderSizePixel = 0, - Size = UDim2.fromOffset(200, 40), - [React.Event.Activated] = props.onActivated, - }) -end - -return ReactButton \ No newline at end of file diff --git a/src/Components/Button.story.luau b/src/Components/Button.story.luau deleted file mode 100644 index 1b4565ce..00000000 --- a/src/Components/Button.story.luau +++ /dev/null @@ -1,23 +0,0 @@ -local React = require(script.Parent.Parent.Parent.react) -local ReactRoblox = require(script.Parent.Parent.Parent["react-roblox"]) - -return { - story = function() - return React.createElement("TextButton", { - Text = "Click Me", - TextSize = 16, - Font = Enum.Font.BuilderSansExtraBold, - TextColor3 = Color3.fromRGB(50, 50, 50), - BackgroundColor3 = Color3.fromRGB(255, 255, 255), - BorderSizePixel = 0, - Size = UDim2.fromOffset(200, 40), - [React.Event.Activated] = function() - print("clicked") - end, - }) - end, - packages = { - React = React, - ReactRoblox = ReactRoblox, - }, -} \ No newline at end of file From d6d92f261eb00600c0781d226f64d611bc678c4c Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 14 Feb 2026 01:16:05 +0000 Subject: [PATCH 009/186] Add Slot component Signed-off-by: GitHub --- src/Components/Slot.luau | 84 ++++++++++++++++++++++++++++++++++ src/Components/Slot.story.luau | 40 ++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 src/Components/Slot.luau create mode 100644 src/Components/Slot.story.luau diff --git a/src/Components/Slot.luau b/src/Components/Slot.luau new file mode 100644 index 00000000..29d0492f --- /dev/null +++ b/src/Components/Slot.luau @@ -0,0 +1,84 @@ +local UserInputService = game:GetService("UserInputService") + +local React = require(script.Parent.Parent.Parent.react) + +local Tooltip = require(script.Parent.Tooltip) + +export type Props = { + tool: Tool?, + slotNumber: number?, + equipped: boolean?, + forceVisible: boolean?, + unlocked: boolean?, + order: number?, + onActivated: (() -> ())?, + children: any?, +} + +local function Slot(props: Props) + local toolName = props.tool and props.tool.Name + local toolImage = props.tool and props.tool.TextureId + local tooltipText = props.tool and props.tool.ToolTip + + -- Only show hint if keyboard and mouse is preferred or forced visible + local isKeyboardAndMousePreferred, setIsKeyboardAndMousePreferred = + React.useState(UserInputService.PreferredInput == Enum.PreferredInput.KeyboardAndMouse) + + React.useEffect(function() + local function preferredInputChanged() + local preferredInput = UserInputService.PreferredInput + + if preferredInput == Enum.PreferredInput.KeyboardAndMouse then + setIsKeyboardAndMousePreferred(true) + else + setIsKeyboardAndMousePreferred(false) + end + end + + preferredInputChanged() + local signal: RBXScriptConnection = UserInputService:GetPropertyChangedSignal("PreferredInput") + :Connect(preferredInputChanged) + + return function() + signal:Disconnect() + end + end, {}) + + local visible = props.forceVisible == true or isKeyboardAndMousePreferred + + -- Generate tags based on state + local tags = "Slot" + if props.unlocked then + tags = tags .. " Unlocked" + end + if props.equipped then + tags = tags .. " Equipped" + end + + -- Hide name if there is an image + local slotText = toolName + if toolImage ~= "" then + slotText = "" + end + + return React.createElement("TextButton", { + Text = slotText, + LayoutOrder = props.order, + Visible = visible, + [React.Tag] = tags, + [React.Event.Activated] = props.onActivated, + }, { + NumberHint = React.createElement("TextLabel", { + Text = props.slotNumber or 0, + [React.Tag] = "SlotNumber", + }), + TextureIcon = React.createElement("ImageLabel", { + Image = toolImage or "", + }), + ToolTip = React.createElement(Tooltip, { + text = tooltipText, + }), + }, props.children) +end + +return Slot \ No newline at end of file diff --git a/src/Components/Slot.story.luau b/src/Components/Slot.story.luau new file mode 100644 index 00000000..70e014c8 --- /dev/null +++ b/src/Components/Slot.story.luau @@ -0,0 +1,40 @@ +local React = require(script.Parent.Parent.Parent.react) + +local Slot = require(script.Parent.Slot) + +local controls = { + toolName = "Sword", + slotNumber = 9, + toolImage = "rbxasset://Textures/Sword128.png", + tooltipText = "A classic sword", + equipped = false, + unlocked = false, + forceNumberVisible = true, +} + +type Props = { + controls: typeof(controls), +} + +return { + summary = "Text button that can hold a tool", + controls = controls, + story = function(props: Props) + local Tool = Instance.new("Tool") + Tool.Name = props.controls.toolName + Tool.TextureId = props.controls.toolImage + Tool.ToolTip = props.controls.tooltipText + + return React.createElement(Slot, { + tool = Tool, + slotNumber = props.controls.slotNumber, + equipped = props.controls.equipped, + unlocked = props.controls.unlocked, + forceVisible = props.controls.forceNumberVisible, + }, { + StyleLink = React.createElement("StyleLink", { + StyleSheet = script.Parent.Parent.StyleSheets.SatchelStyleSheet, + }), + }) + end, +} From 2f230059b7b782d5ce65bf0a0d57b7c9040f9307 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 14 Feb 2026 01:38:16 +0000 Subject: [PATCH 010/186] Remove style link child Signed-off-by: GitHub --- src/Components/Satchel.storybook.luau | 15 ++++++++++++++- src/Components/Slot.luau | 5 ++--- src/Components/Slot.story.luau | 4 ---- src/Components/Tooltip.luau | 3 +-- src/Components/Tooltip.story.luau | 4 ---- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/Components/Satchel.storybook.luau b/src/Components/Satchel.storybook.luau index 3aa95e33..9cf9ec1b 100644 --- a/src/Components/Satchel.storybook.luau +++ b/src/Components/Satchel.storybook.luau @@ -1,8 +1,21 @@ local React = require(script.Parent.Parent.Parent.react) local ReactRoblox = require(script.Parent.Parent.Parent["react-roblox"]) +local DESIGN_SHEET = script.Parent.Parent.StyleSheets.SatchelStyleSheet + return { name = "Satchel", + mapStory = function(Story) + return function(storyProps) + return React.createElement(React.Fragment, nil, { + StyleLink = React.createElement("StyleLink", { + StyleSheet = DESIGN_SHEET, + }), + + Story = React.createElement(Story, storyProps), + }) + end + end, storyRoots = { script.Parent, }, @@ -10,4 +23,4 @@ return { React = React, ReactRoblox = ReactRoblox, }, -} \ No newline at end of file +} diff --git a/src/Components/Slot.luau b/src/Components/Slot.luau index 29d0492f..87c6d6fe 100644 --- a/src/Components/Slot.luau +++ b/src/Components/Slot.luau @@ -12,7 +12,6 @@ export type Props = { unlocked: boolean?, order: number?, onActivated: (() -> ())?, - children: any?, } local function Slot(props: Props) @@ -78,7 +77,7 @@ local function Slot(props: Props) ToolTip = React.createElement(Tooltip, { text = tooltipText, }), - }, props.children) + }) end -return Slot \ No newline at end of file +return Slot diff --git a/src/Components/Slot.story.luau b/src/Components/Slot.story.luau index 70e014c8..4feb6a60 100644 --- a/src/Components/Slot.story.luau +++ b/src/Components/Slot.story.luau @@ -31,10 +31,6 @@ return { equipped = props.controls.equipped, unlocked = props.controls.unlocked, forceVisible = props.controls.forceNumberVisible, - }, { - StyleLink = React.createElement("StyleLink", { - StyleSheet = script.Parent.Parent.StyleSheets.SatchelStyleSheet, - }), }) end, } diff --git a/src/Components/Tooltip.luau b/src/Components/Tooltip.luau index d190584d..d8fc3aa4 100644 --- a/src/Components/Tooltip.luau +++ b/src/Components/Tooltip.luau @@ -2,7 +2,6 @@ local React = require(script.Parent.Parent.Parent.react) export type Props = { text: string?, - children: any?, } local function Tooltip(props: Props) @@ -14,7 +13,7 @@ local function Tooltip(props: Props) return React.createElement("TextLabel", { Text = props.text, [React.Tag] = "Tooltip", - }, props.children) + }) end return Tooltip diff --git a/src/Components/Tooltip.story.luau b/src/Components/Tooltip.story.luau index 9e0076fc..355eba2f 100644 --- a/src/Components/Tooltip.story.luau +++ b/src/Components/Tooltip.story.luau @@ -16,10 +16,6 @@ return { story = function(props: Props) return React.createElement(Tooltip, { text = props.controls.text, - }, { - StyleLink = React.createElement("StyleLink", { - StyleSheet = script.Parent.Parent.StyleSheets.SatchelStyleSheet, - }), }) end, } From c941c1f3e4b59e10af79b4f0dc838bb755727939 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 19 Feb 2026 02:02:20 -0800 Subject: [PATCH 011/186] Add back missing components Signed-off-by: Ryan Luu --- src/Components/Hotbar.luau | 27 ++++++++++++++++ src/Components/Hotbar.story.luau | 42 +++++++++++++++++++++++++ src/Components/HotbarHint.luau | 46 ++++++++++++++++++++++++++++ src/Components/HotbarHint.story.luau | 22 +++++++++++++ 4 files changed, 137 insertions(+) create mode 100644 src/Components/Hotbar.luau create mode 100644 src/Components/Hotbar.story.luau create mode 100644 src/Components/HotbarHint.luau create mode 100644 src/Components/HotbarHint.story.luau diff --git a/src/Components/Hotbar.luau b/src/Components/Hotbar.luau new file mode 100644 index 00000000..be0f8c2b --- /dev/null +++ b/src/Components/Hotbar.luau @@ -0,0 +1,27 @@ +local React = require(script.Parent.Parent.Parent.react) + +local HotbarHint = require(script.Parent.HotbarHint) + +export type Props = { + forceHintVisible: boolean?, +} + +local function Hotbar(props: Props) + return React.createElement("Frame", { + [React.Tag] = "Hotbar", + }, { + -- Create default hints for switching between hotbar slots + SlotLeftHint = React.createElement(HotbarHint, { + hintKey = Enum.KeyCode.ButtonL1, + forceVisible = props.forceHintVisible, + order = -1, + }), + SlotRightHint = React.createElement(HotbarHint, { + hintKey = Enum.KeyCode.ButtonR1, + forceVisible = props.forceHintVisible, + order = 100, + }), + }) +end + +return Hotbar diff --git a/src/Components/Hotbar.story.luau b/src/Components/Hotbar.story.luau new file mode 100644 index 00000000..af5ab760 --- /dev/null +++ b/src/Components/Hotbar.story.luau @@ -0,0 +1,42 @@ +local React = require(script.Parent.Parent.Parent.react) + +local Hotbar = require(script.Parent.Hotbar) +local Slot = require(script.Parent.Slot) + +local controls = { + forceHintVisible = true, + toolName = "Sword", + slotNumber = 9, + toolImage = "rbxasset://Textures/Sword128.png", + tooltipText = "A classic sword", +} + +type Props = { + controls: typeof(controls), +} + +return { + summary = "Hotbar component that holds hotbar slots and hints", + controls = controls, + story = function(props: Props) + local Tool = Instance.new("Tool") + Tool.Name = props.controls.toolName + Tool.TextureId = props.controls.toolImage + Tool.ToolTip = props.controls.tooltipText + + local component = React.createElement(Hotbar, { + forceHintVisible = props.controls.forceHintVisible, + }, { + Tool = React.createElement(Slot, { + tool = Tool, + slotNumber = 1, + order = 1, + }), + StyleLink = React.createElement("StyleLink", { + StyleSheet = script.Parent.Parent.StyleSheets.SatchelStyleSheet, + }), + }) + + return component + end, +} diff --git a/src/Components/HotbarHint.luau b/src/Components/HotbarHint.luau new file mode 100644 index 00000000..a688a228 --- /dev/null +++ b/src/Components/HotbarHint.luau @@ -0,0 +1,46 @@ +local UserInputService = game:GetService("UserInputService") + +local React = require(script.Parent.Parent.Parent.react) + +export type Props = { + hintKey: Enum.KeyCode, + forceVisible: boolean?, + order: number?, +} + +local function HotbarHint(props: Props) + -- Only show hint if gamepad is preferred or forced visible + local isGamepadPreferred, setIsGamepadPreferred = + React.useState(UserInputService.PreferredInput == Enum.PreferredInput.Gamepad) + + React.useEffect(function() + local function preferredInputChanged() + local preferredInput = UserInputService.PreferredInput + + if preferredInput == Enum.PreferredInput.Gamepad then + setIsGamepadPreferred(true) + else + setIsGamepadPreferred(false) + end + end + + preferredInputChanged() + local signal: RBXScriptConnection = UserInputService:GetPropertyChangedSignal("PreferredInput") + :Connect(preferredInputChanged) + + return function() + signal:Disconnect() + end + end, {}) + + local visible = props.forceVisible == true or isGamepadPreferred + + return React.createElement("ImageLabel", { + Image = UserInputService:GetImageForKeyCode(props.hintKey), + LayoutOrder = props.order, + Visible = visible, + [React.Tag] = "HintSlot", + }) +end + +return HotbarHint diff --git a/src/Components/HotbarHint.story.luau b/src/Components/HotbarHint.story.luau new file mode 100644 index 00000000..405b2fd1 --- /dev/null +++ b/src/Components/HotbarHint.story.luau @@ -0,0 +1,22 @@ +local React = require(script.Parent.Parent.Parent.react) + +local HotbarHint = require(script.Parent.HotbarHint) + +local controls = { + forceVisible = true, +} + +type Props = { + controls: typeof(controls), +} + +return { + summary = "Hint for switching to a hotbar slot, displayed when gamepad is preferred or forced visible", + controls = controls, + story = function(props: Props) + return React.createElement(HotbarHint, { + hintKey = Enum.KeyCode.ButtonX, + forceVisible = props.controls.forceVisible, + }) + end, +} From a3a9cbee2b45b2103706ed9b956d86a24c98c3a4 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 19 Feb 2026 02:20:40 -0800 Subject: [PATCH 012/186] Enable strict types on supported components Signed-off-by: Ryan Luu --- src/Components/HotbarHint.luau | 2 ++ src/Components/Satchel.storybook.luau | 2 ++ src/Components/Slot.luau | 2 ++ src/Components/Tooltip.story.luau | 2 ++ 4 files changed, 8 insertions(+) diff --git a/src/Components/HotbarHint.luau b/src/Components/HotbarHint.luau index a688a228..6e1c6e74 100644 --- a/src/Components/HotbarHint.luau +++ b/src/Components/HotbarHint.luau @@ -1,3 +1,5 @@ +--!strict + local UserInputService = game:GetService("UserInputService") local React = require(script.Parent.Parent.Parent.react) diff --git a/src/Components/Satchel.storybook.luau b/src/Components/Satchel.storybook.luau index 9cf9ec1b..fd8cb985 100644 --- a/src/Components/Satchel.storybook.luau +++ b/src/Components/Satchel.storybook.luau @@ -1,3 +1,5 @@ +--!strict + local React = require(script.Parent.Parent.Parent.react) local ReactRoblox = require(script.Parent.Parent.Parent["react-roblox"]) diff --git a/src/Components/Slot.luau b/src/Components/Slot.luau index 87c6d6fe..89f9153c 100644 --- a/src/Components/Slot.luau +++ b/src/Components/Slot.luau @@ -1,3 +1,5 @@ +--!strict + local UserInputService = game:GetService("UserInputService") local React = require(script.Parent.Parent.Parent.react) diff --git a/src/Components/Tooltip.story.luau b/src/Components/Tooltip.story.luau index 355eba2f..60d857d3 100644 --- a/src/Components/Tooltip.story.luau +++ b/src/Components/Tooltip.story.luau @@ -1,3 +1,5 @@ +--!strict + local React = require(script.Parent.Parent.Parent.react) local Tooltip = require(script.Parent.Tooltip) From 3a5db8a4f7ae888593ab893aa9772a34c82187db Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 20 Feb 2026 01:50:57 -0800 Subject: [PATCH 013/186] Add model files for StyleSheets Signed-off-by: Ryan Luu --- src/Design/BaseTokens.model.json | 106 +++++ src/Design/DefaultTheme.model.json | 13 + src/Design/DesignTokens.model.json | 13 + src/Design/LegacyTheme.model.json | 90 +++++ src/Design/SatchelStyleSheet.model.json | 511 ++++++++++++++++++++++++ 5 files changed, 733 insertions(+) create mode 100644 src/Design/BaseTokens.model.json create mode 100644 src/Design/DefaultTheme.model.json create mode 100644 src/Design/DesignTokens.model.json create mode 100644 src/Design/LegacyTheme.model.json create mode 100644 src/Design/SatchelStyleSheet.model.json diff --git a/src/Design/BaseTokens.model.json b/src/Design/BaseTokens.model.json new file mode 100644 index 00000000..668f3897 --- /dev/null +++ b/src/Design/BaseTokens.model.json @@ -0,0 +1,106 @@ +{ + "ClassName": "StyleSheet", + "Attributes": { + "ContainerBackgroundColor": "$BackgroundColor", + "ContainerBackgroundTransparency": 0.2, + "ContainerCornerRadius": "$SmallCornerRadius", + "ContainerStrokeColor": [ + 1, + 1, + 1 + ], + "ContainerStrokeTransparency": 0.8, + "HintFontFace": "$FontFace", + "HintTextColor": "$TextColor", + "HintTextSize": "$TextSize", + "SearchFontFace": "$FontFace", + "SearchPadding": { + "UDim": [ + 0, + 8 + ] + }, + "SearchPlaceholderColor": [ + 0.698039, + 0.698039, + 0.698039 + ], + "SearchTextColor": "$TextColor", + "SearchTextSize": "$TextSize", + "SearchTextStrokeTransparency": "$TextStrokeTransparency", + "SlotBackgroundColor": [ + 0.098039, + 0.105882, + 0.113725 + ], + "SlotBackgroundTransparency": 0.3, + "SlotCornerRadius": "$SmallCornerRadius", + "SlotEquipStrokeColor": [ + 1, + 1, + 1 + ], + "SlotEquipStrokeThickness": 4, + "SlotFontFace": "$FontFace", + "SlotIconCornerRadius": { + "UDim": [ + 0, + 0 + ] + }, + "SlotNumberFontFace": "$FontFace", + "SlotNumberStrokeColor": "$TextStrokeColor", + "SlotNumberStrokeTransparency": "$TextStrokeTransparency", + "SlotNumberTextColor": "$TextColor", + "SlotNumberTextSize": "$SmallTextSize", + "SlotPadding": { + "UDim": [ + 0, + 5 + ] + }, + "SlotPressStrokeColor": [ + 1, + 1, + 1 + ], + "SlotTextColor": "$TextColor", + "SlotTextSize": "$TextSize", + "SlotTextStrokeColor": "$TextStrokeColor", + "SlotTextStrokeTransparency": "$TextStrokeTransparency", + "SlotUnlockBackgroundColor": "$SlotBackgroundColor", + "StyleCategory": "Tokens", + "SurfaceBackgroundColor": "$BackgroundColor", + "SurfaceBackgroundTransparency": 0.3, + "SurfaceCornerRadius": "$CornerRadius", + "SurfacePadding": { + "UDim": [ + 0, + 5 + ] + }, + "ToolTipBackgroundColor": [ + 0.149019, + 0.156862, + 0.188235 + ], + "ToolTipBackgroundTranparency": 0, + "ToolTipCornerRadius": "$SmallCornerRadius", + "ToolTipFontFace": "$FontFace", + "ToolTipPadding": { + "UDim": [ + 0, + 4 + ] + }, + "ToolTipTextColor": "$TextColor", + "ToolTipTextSize": "$SmallTextSize" + }, + "Children": [ + { + "Name": "Derive from DesignTokens", + "ClassName": "StyleDerive", + "Properties": {} + } + ] +} \ No newline at end of file diff --git a/src/Design/DefaultTheme.model.json b/src/Design/DefaultTheme.model.json new file mode 100644 index 00000000..9edcaee0 --- /dev/null +++ b/src/Design/DefaultTheme.model.json @@ -0,0 +1,13 @@ +{ + "ClassName": "StyleSheet", + "Attributes": { + "StyleCategory": "Themes" + }, + "Children": [ + { + "Name": "Derive from BaseTokens", + "ClassName": "StyleDerive", + "Properties": {} + } + ] +} \ No newline at end of file diff --git a/src/Design/DesignTokens.model.json b/src/Design/DesignTokens.model.json new file mode 100644 index 00000000..9edcaee0 --- /dev/null +++ b/src/Design/DesignTokens.model.json @@ -0,0 +1,13 @@ +{ + "ClassName": "StyleSheet", + "Attributes": { + "StyleCategory": "Themes" + }, + "Children": [ + { + "Name": "Derive from BaseTokens", + "ClassName": "StyleDerive", + "Properties": {} + } + ] +} \ No newline at end of file diff --git a/src/Design/LegacyTheme.model.json b/src/Design/LegacyTheme.model.json new file mode 100644 index 00000000..515b107f --- /dev/null +++ b/src/Design/LegacyTheme.model.json @@ -0,0 +1,90 @@ +{ + "ClassName": "StyleSheet", + "Attributes": { + "ContainerBackgroundColor": [ + 0.368627, + 0.368627, + 0.368627 + ], + "ContainerStrokeTransparency": 1, + "CornerRadius": { + "UDim": [ + 0, + 0 + ] + }, + "FontFace": { + "family": "rbxasset://fonts/families/SourceSansPro.json", + "weight": "Regular", + "style": "Normal" + }, + "HintFontFace": { + "family": "rbxasset://fonts/families/SourceSansPro.json", + "weight": "Bold", + "style": "Normal" + }, + "HintTextSize": 24, + "SearchPadding": { + "UDim": [ + 0, + 0 + ] + }, + "SearchPlaceholderColor": [ + 1, + 1, + 1 + ], + "SearchTextSize": 24, + "SlotBackgroundColor": [ + 0.121568, + 0.121568, + 0.121568 + ], + "SlotEquipStrokeColor": [ + 0.352941, + 0.556862, + 0.913725 + ], + "SlotEquipStrokeThickness": 5, + "SlotPadding": { + "UDim": [ + 0, + 6 + ] + }, + "SlotUnlockBackgroundColor": [ + 0.192156, + 0.192156, + 0.192156 + ], + "SmallCornerRadius": { + "UDim": [ + 0, + 0 + ] + }, + "SmallTextSize": 14, + "StyleCategory": "Themes", + "TextSize": 14, + "TextStrokeTransparency": 1, + "ToolTipBackgroundColor": [ + 0.400000, + 0.400000, + 0.400000 + ], + "ToolTipPadding": { + "UDim": [ + 0, + 2 + ] + } + }, + "Children": [ + { + "Name": "Derive from BaseTokens", + "ClassName": "StyleDerive", + "Properties": {} + } + ] +} \ No newline at end of file diff --git a/src/Design/SatchelStyleSheet.model.json b/src/Design/SatchelStyleSheet.model.json new file mode 100644 index 00000000..35494afe --- /dev/null +++ b/src/Design/SatchelStyleSheet.model.json @@ -0,0 +1,511 @@ +{ + "ClassName": "StyleSheet", + "Properties": {}, + "Children": [ + { + "Name": ".Hotbar", + "ClassName": "StyleRule", + "Properties": { + "Priority": 5, + "Selector": ".Hotbar" + }, + "Children": [ + { + "Name": "::UIListLayout", + "ClassName": "StyleRule", + "Properties": { + "Priority": 1, + "Selector": "::UIListLayout" + } + } + ] + }, + { + "Name": ".Hints", + "ClassName": "StyleRule", + "Properties": { + "Priority": 6, + "Selector": ".Hints" + }, + "Children": [ + { + "Name": "::UIListLayout", + "ClassName": "StyleRule", + "Properties": { + "Priority": 1, + "Selector": "::UIListLayout" + } + } + ] + }, + { + "Name": ".Backpack", + "ClassName": "StyleRule", + "Properties": { + "Priority": 8, + "Selector": ".Backpack" + }, + "Children": [ + { + "Name": "::UIPadding", + "ClassName": "StyleRule", + "Properties": { + "Priority": 2, + "Selector": "::UIPadding" + } + }, + { + "Name": "::UIListLayout", + "ClassName": "StyleRule", + "Properties": { + "Priority": 1, + "Selector": "::UIListLayout" + } + } + ] + }, + { + "Name": "ImageLabel", + "ClassName": "StyleRule", + "Properties": { + "Priority": 5, + "Selector": "ImageLabel" + }, + "Children": [ + { + "Name": ".HintSlot", + "ClassName": "StyleRule", + "Properties": { + "Priority": 1, + "Selector": ".HintSlot" + }, + "Children": [ + { + "Name": "::UIAspectRatioConstraint", + "ClassName": "StyleRule", + "Properties": { + "Priority": 1, + "Selector": "::UIAspectRatioConstraint" + } + } + ] + } + ] + }, + { + "Name": "Derive from DefaultTheme", + "ClassName": "StyleDerive", + "Properties": {} + }, + { + "Name": "TextBox", + "ClassName": "StyleRule", + "Properties": { + "Priority": 7, + "Selector": "TextBox" + }, + "Children": [ + { + "Name": ".SearchBar", + "ClassName": "StyleRule", + "Properties": { + "Priority": 2, + "Selector": ".SearchBar" + }, + "Children": [ + { + "Name": "::UIPadding", + "ClassName": "StyleRule", + "Properties": { + "Priority": 1, + "Selector": "::UIPadding" + } + }, + { + "Name": ">ImageButton", + "ClassName": "StyleRule", + "Properties": { + "Priority": 3, + "Selector": ">ImageButton" + }, + "Children": [ + { + "Name": "::UIAspectRatioConstraint", + "ClassName": "StyleRule", + "Properties": { + "Priority": 1, + "Selector": "::UIAspectRatioConstraint" + } + } + ] + } + ] + } + ] + }, + { + "Name": "ScrollingFrame", + "ClassName": "StyleRule", + "Properties": { + "Priority": 11, + "Selector": "ScrollingFrame" + } + }, + { + "Name": ".Surface,.Hints,.Inventory", + "ClassName": "StyleRule", + "Properties": { + "Priority": 3, + "Selector": ".Surface,.Hints,.Inventory" + }, + "Children": [ + { + "Name": "::UIPadding", + "ClassName": "StyleRule", + "Properties": { + "Priority": 2, + "Selector": "::UIPadding" + } + }, + { + "Name": "::UICorner", + "ClassName": "StyleRule", + "Properties": { + "Priority": 1, + "Selector": "::UICorner" + } + } + ] + }, + { + "Name": "ImageButton", + "ClassName": "StyleRule", + "Properties": { + "Priority": 6, + "Selector": "ImageButton" + } + }, + { + "Name": ".Inventory", + "ClassName": "StyleRule", + "Properties": { + "Priority": 7, + "Selector": ".Inventory" + }, + "Children": [ + { + "Name": ">ScrollingFrame", + "ClassName": "StyleRule", + "Properties": { + "Priority": 1, + "Selector": ">ScrollingFrame" + }, + "Children": [ + { + "Name": "::UIListLayout", + "ClassName": "StyleRule", + "Properties": { + "Priority": 2, + "Selector": "::UIListLayout" + } + } + ] + }, + { + "Name": "::UIListLayout", + "ClassName": "StyleRule", + "Properties": { + "Priority": 1, + "Selector": "::UIListLayout" + } + } + ] + }, + { + "Name": "Frame", + "ClassName": "StyleRule", + "Properties": { + "Priority": 12, + "Selector": "Frame" + }, + "Children": [ + { + "Name": ".Hint", + "ClassName": "StyleRule", + "Properties": { + "Priority": 2, + "Selector": ".Hint" + }, + "Children": [ + { + "Name": ">TextLabel", + "ClassName": "StyleRule", + "Properties": { + "Priority": 3, + "Selector": ">TextLabel" + } + }, + { + "Name": ">ImageLabel", + "ClassName": "StyleRule", + "Properties": { + "Priority": 4, + "Selector": ">ImageLabel" + }, + "Children": [ + { + "Name": "::UIAspectRatioConstraint", + "ClassName": "StyleRule", + "Properties": { + "Priority": 1, + "Selector": "::UIAspectRatioConstraint" + } + } + ] + } + ] + } + ] + }, + { + "Name": "TextLabel", + "ClassName": "StyleRule", + "Properties": { + "Priority": 10, + "Selector": "TextLabel" + }, + "Children": [ + { + "Name": ".Tooltip", + "ClassName": "StyleRule", + "Properties": { + "Priority": 9, + "Selector": ".Tooltip" + }, + "Children": [ + { + "Name": "::UIPadding", + "ClassName": "StyleRule", + "Properties": { + "Priority": 2, + "Selector": "::UIPadding" + } + }, + { + "Name": "::UICorner", + "ClassName": "StyleRule", + "Properties": { + "Priority": 1, + "Selector": "::UICorner" + } + } + ] + } + ] + }, + { + "Name": ".Container,.SearchBar", + "ClassName": "StyleRule", + "Properties": { + "Priority": 3, + "Selector": ".Container,.SearchBar" + }, + "Children": [ + { + "Name": "::UIStroke", + "ClassName": "StyleRule", + "Properties": { + "Priority": 2, + "Selector": "::UIStroke" + } + }, + { + "Name": "::UIPadding", + "ClassName": "StyleRule", + "Properties": { + "Priority": 2, + "Selector": "::UIPadding" + } + }, + { + "Name": "::UICorner", + "ClassName": "StyleRule", + "Properties": { + "Priority": 1, + "Selector": "::UICorner" + } + } + ] + }, + { + "Name": "TextButton", + "ClassName": "StyleRule", + "Properties": { + "Priority": 8, + "Selector": "TextButton" + }, + "Children": [ + { + "Name": ".Slot", + "ClassName": "StyleRule", + "Properties": { + "Priority": 2, + "Selector": ".Slot" + }, + "Children": [ + { + "Name": ">ImageLabel", + "ClassName": "StyleRule", + "Properties": { + "Priority": 7, + "Selector": ">ImageLabel" + }, + "Children": [ + { + "Name": "::UICorner", + "ClassName": "StyleRule", + "Properties": { + "Priority": 1, + "Selector": "::UICorner" + } + } + ] + }, + { + "Name": ":Press", + "ClassName": "StyleRule", + "Properties": { + "Priority": 9, + "Selector": ":Press" + }, + "Children": [ + { + "Name": ">.Tooltip", + "ClassName": "StyleRule", + "Properties": { + "Priority": 2, + "Selector": ">.Tooltip" + } + } + ] + }, + { + "Name": "::UIPadding", + "ClassName": "StyleRule", + "Properties": { + "Priority": 5, + "Selector": "::UIPadding" + } + }, + { + "Name": ".Unlocked", + "ClassName": "StyleRule", + "Properties": { + "Priority": 11, + "Selector": ".Unlocked" + }, + "Children": [ + { + "Name": ":Press", + "ClassName": "StyleRule", + "Properties": { + "Priority": 9, + "Selector": ":Press" + }, + "Children": [ + { + "Name": "::UIStroke", + "ClassName": "StyleRule", + "Properties": { + "Priority": 1, + "Selector": "::UIStroke" + } + } + ] + } + ] + }, + { + "Name": ":Hover", + "ClassName": "StyleRule", + "Properties": { + "Priority": 8, + "Selector": ":Hover" + }, + "Children": [ + { + "Name": ">.Tooltip", + "ClassName": "StyleRule", + "Properties": { + "Priority": 1, + "Selector": ">.Tooltip" + } + } + ] + }, + { + "Name": ">TextLabel", + "ClassName": "StyleRule", + "Properties": { + "Priority": 4, + "Selector": ">TextLabel" + }, + "Children": [ + { + "Name": ".Tooltip", + "ClassName": "StyleRule", + "Properties": { + "Priority": 9, + "Selector": ".Tooltip" + } + }, + { + "Name": ".SlotNumber", + "ClassName": "StyleRule", + "Properties": { + "Priority": 1, + "Selector": ".SlotNumber" + } + } + ] + }, + { + "Name": "::UICorner", + "ClassName": "StyleRule", + "Properties": { + "Priority": 1, + "Selector": "::UICorner" + } + }, + { + "Name": ".Equipped", + "ClassName": "StyleRule", + "Properties": { + "Priority": 10, + "Selector": ".Equipped" + }, + "Children": [ + { + "Name": "::UIStroke", + "ClassName": "StyleRule", + "Properties": { + "Priority": 1, + "Selector": "::UIStroke" + } + } + ] + }, + { + "Name": "::UITextSizeConstraint", + "ClassName": "StyleRule", + "Properties": { + "Priority": 6, + "Selector": "::UITextSizeConstraint" + } + } + ] + } + ] + } + ] +} \ No newline at end of file From cbfc439f7f923fa49ef774a387024e22a97cfa09 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 20 Feb 2026 13:33:27 -0800 Subject: [PATCH 014/186] Rename design tokens to theme tokens Signed-off-by: Ryan Luu --- src/Design/BaseTokens.model.json | 2 +- src/Design/{DesignTokens.model.json => ThemeTokens.model.json} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/Design/{DesignTokens.model.json => ThemeTokens.model.json} (100%) diff --git a/src/Design/BaseTokens.model.json b/src/Design/BaseTokens.model.json index 668f3897..b0e03990 100644 --- a/src/Design/BaseTokens.model.json +++ b/src/Design/BaseTokens.model.json @@ -98,7 +98,7 @@ }, "Children": [ { - "Name": "Derive from DesignTokens", + "Name": "Derive from ThemeTokens", "ClassName": "StyleDerive", "Properties": {} } diff --git a/src/Design/DesignTokens.model.json b/src/Design/ThemeTokens.model.json similarity index 100% rename from src/Design/DesignTokens.model.json rename to src/Design/ThemeTokens.model.json From 55c8682b2a234d4524c401f901bda8dbd8d290c2 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 20 Feb 2026 13:42:22 -0800 Subject: [PATCH 015/186] Remove style link Signed-off-by: Ryan Luu --- src/Components/Hotbar.story.luau | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Components/Hotbar.story.luau b/src/Components/Hotbar.story.luau index af5ab760..e3fac614 100644 --- a/src/Components/Hotbar.story.luau +++ b/src/Components/Hotbar.story.luau @@ -32,9 +32,6 @@ return { slotNumber = 1, order = 1, }), - StyleLink = React.createElement("StyleLink", { - StyleSheet = script.Parent.Parent.StyleSheets.SatchelStyleSheet, - }), }) return component From bef0a0202987949d61f7b206440445493061a483 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 20 Feb 2026 14:06:04 -0800 Subject: [PATCH 016/186] Move away from model based files Signed-off-by: Ryan Luu --- src/Components/Satchel.storybook.luau | 2 +- src/{StyleSheets.rbxmx => Design.rbxmx} | 450 ++++++--------------- src/Design/BaseTokens.model.json | 106 ----- src/Design/DefaultTheme.model.json | 13 - src/Design/LegacyTheme.model.json | 90 ----- src/Design/SatchelStyleSheet.model.json | 511 ------------------------ src/Design/ThemeTokens.model.json | 13 - 7 files changed, 130 insertions(+), 1055 deletions(-) rename src/{StyleSheets.rbxmx => Design.rbxmx} (71%) delete mode 100644 src/Design/BaseTokens.model.json delete mode 100644 src/Design/DefaultTheme.model.json delete mode 100644 src/Design/LegacyTheme.model.json delete mode 100644 src/Design/SatchelStyleSheet.model.json delete mode 100644 src/Design/ThemeTokens.model.json diff --git a/src/Components/Satchel.storybook.luau b/src/Components/Satchel.storybook.luau index fd8cb985..563e3722 100644 --- a/src/Components/Satchel.storybook.luau +++ b/src/Components/Satchel.storybook.luau @@ -3,7 +3,7 @@ local React = require(script.Parent.Parent.Parent.react) local ReactRoblox = require(script.Parent.Parent.Parent["react-roblox"]) -local DESIGN_SHEET = script.Parent.Parent.StyleSheets.SatchelStyleSheet +local DESIGN_SHEET = script.Parent.Parent.Design.SatchelStyleSheet return { name = "Satchel", diff --git a/src/StyleSheets.rbxmx b/src/Design.rbxmx similarity index 71% rename from src/StyleSheets.rbxmx rename to src/Design.rbxmx index 59c840ae..7f80862f 100644 --- a/src/StyleSheets.rbxmx +++ b/src/Design.rbxmx @@ -2,16 +2,16 @@ true null nil - + 0 false - StyleSheets + Design -1 - + 0 @@ -20,10 +20,11 @@ -1 - + 12 AAAAAA== + Frame 0 @@ -32,11 +33,12 @@ -1 - + 2 + .Hint 0 @@ -45,7 +47,7 @@ dW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/BAAAAFNpemUKAAAAAAAAAAAAAAAAKAAAAA==]]>-1 - + 3 + >TextLabel 0 @@ -62,11 +65,12 @@ bG9yCAAAAFRleHRTaXplAg0AAAAkSGludFRleHRTaXpl]]> - + 4 + >ImageLabel 0 @@ -75,10 +79,11 @@ AAAABAAAAFNpemUKAAAAACUAAAAAAAAAJQAAAA==]]> -1 - + 1 AAAAAA== + ::UIAspectRatioConstraint 0 @@ -91,10 +96,11 @@ AAAABAAAAFNpemUKAAAAACUAAAAAAAAAJQAAAA==]]> - + 11 AAAAAA== + ScrollingFrame 0 @@ -104,10 +110,11 @@ AAAABAAAAFNpemUKAAAAACUAAAAAAAAAJQAAAA==]]> - + 10 AAAAAA== + TextLabel 0 @@ -116,7 +123,7 @@ AAAABAAAAFNpemUKAAAAACUAAAAAAAAAJQAAAA==]]> -1 - + 9 + .Tooltip 0 @@ -134,10 +142,11 @@ ZXh0U2l6ZQ==]]> -1 - + 1 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz + ::UICorner 0 @@ -147,12 +156,13 @@ ZXh0U2l6ZQ==]]> - + 2 + ::UIPadding 0 @@ -164,10 +174,11 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkVG9vbFRpcFBhZGRpbmc=]]> - + 8 AAAAAA== + TextButton 0 @@ -176,7 +187,7 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkVG9vbFRpcFBhZGRpbmc=]]> -1 - + 2 + .Slot 0 @@ -194,10 +206,11 @@ cmFuc3BhcmVuY3kMAAAAVGV4dFRydW5jYXRlFQwAAABUZXh0VHJ1bmNhdGUCAAAA]]>-1 - + 10 AAAAAA== + .Equipped 0 @@ -206,13 +219,14 @@ cmFuc3BhcmVuY3kMAAAAVGV4dFRydW5jYXRlFQwAAABUZXh0VHJ1bmNhdGUCAAAA]]>-1 - + 1 + ::UIStroke 0 @@ -223,10 +237,11 @@ b2luTW9kZQAAAAAJAAAAVGhpY2tuZXNzAhkAAAAkU2xvdEVxdWlwU3Ryb2tlVGhpY2tuZXNz - + 8 AAAAAA== + :Hover 0 @@ -235,10 +250,11 @@ b2luTW9kZQAAAAAJAAAAVGhpY2tuZXNzAhkAAAAkU2xvdEVxdWlwU3Ryb2tlVGhpY2tuZXNz -1 - + 1 AQAAAAcAAABWaXNpYmxlAwE= + >.Tooltip 0 @@ -249,11 +265,12 @@ b2luTW9kZQAAAAAJAAAAVGhpY2tuZXNzAhkAAAAkU2xvdEVxdWlwU3Ryb2tlVGhpY2tuZXNz - + 7 + >ImageLabel 0 @@ -262,10 +279,11 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> -1 - + 1 AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== + ::UICorner 0 @@ -276,11 +294,12 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> - + 6 + ::UITextSizeConstraint 0 @@ -290,12 +309,13 @@ AAAAAAAoQA==]]> - + 5 + ::UIPadding 0 @@ -305,10 +325,11 @@ YWRkaW5nVG9wAgwAAAAkU2xvdFBhZGRpbmc=]]> - + 4 AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= + >TextLabel 0 @@ -317,10 +338,11 @@ YWRkaW5nVG9wAgwAAAAkU2xvdFBhZGRpbmc=]]> -1 - + 9 AQAAAAcAAABWaXNpYmxlAwA= + .Tooltip 0 @@ -330,7 +352,7 @@ YWRkaW5nVG9wAgwAAAAkU2xvdFBhZGRpbmc=]]> - + 1 + .SlotNumber 0 @@ -351,10 +374,11 @@ AAAAAEA=]]> - + 1 AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz + ::UICorner 0 @@ -364,11 +388,12 @@ AAAAAEA=]]> - + 11 + .Unlocked 0 @@ -377,10 +402,11 @@ chYAAABCYWNrZ3JvdW5kVHJhbnNwYXJlbmN5BgAAAAAAAAAA]]> -1 - + 9 AAAAAA== + :Press 0 @@ -389,11 +415,12 @@ chYAAABCYWNrZ3JvdW5kVHJhbnNwYXJlbmN5BgAAAAAAAAAA]]> -1 - + 1 + ::UIStroke 0 @@ -405,10 +432,11 @@ b3ICFQAAACRTbG90UHJlc3NTdHJva2VDb2xvcgkAAABUaGlja25lc3MGAAAAAAAAAEA=]]> - + 9 AAAAAA== + :Press 0 @@ -417,10 +445,11 @@ b3ICFQAAACRTbG90UHJlc3NTdHJva2VDb2xvcgkAAABUaGlja25lc3MGAAAAAAAAAEA=]]>-1 - + 2 AQAAAAcAAABWaXNpYmxlAwE= + >.Tooltip 0 @@ -433,10 +462,11 @@ b3ICFQAAACRTbG90UHJlc3NTdHJva2VDb2xvcgkAAABUaGlja25lc3MGAAAAAAAAAEA=]]> - + 7 AAAAAA== + TextBox 0 @@ -445,7 +475,7 @@ b3ICFQAAACRTbG90UHJlc3NTdHJva2VDb2xvcgkAAABUaGlja25lc3MGAAAAAAAAAEA=]]>-1 - + 2 + .SearchBar 0 @@ -462,12 +493,13 @@ YW5zcGFyZW5jeQ4AAABUZXh0WEFsaWdubWVudBUOAAAAVGV4dFhBbGlnbm1lbnQAAAAA]]>-1 - + 1 + ::UIPadding 0 @@ -477,13 +509,14 @@ ZwoAAABQYWRkaW5nVG9wAg4AAAAkU2VhcmNoUGFkZGluZw==]]> - + 3 + >ImageButton 0 @@ -492,10 +525,11 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAAcAAABWaXNpYmxlAwA=]]> -1 - + 1 AAAAAA== + ::UIAspectRatioConstraint 0 @@ -508,10 +542,11 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAAcAAABWaXNpYmxlAwA=]]> - + 6 AAAAAA== + ImageButton 0 @@ -521,10 +556,11 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAAcAAABWaXNpYmxlAwA=]]> - + 5 AAAAAA== + ImageLabel 0 @@ -533,11 +569,12 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAAcAAABWaXNpYmxlAwA=]]> -1 - + 1 + .HintSlot 0 @@ -546,10 +583,11 @@ AAAAU2NhbGVUeXBlAwAAAAQAAABTaXplCgAAAAA8AAAAAAAAADwAAAA=]]> -1 - + 1 AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== + ::UIAspectRatioConstraint 0 @@ -561,22 +599,10 @@ AAAAU2NhbGVUeXBlAwAAAAQAAABTaXplCgAAAAA8AAAAAAAAADwAAAA=]]> - - - 1 - RBX551A91E21149401EBB451F11ACC4116A - - 0 - false - Derive from BaseStyleSheet - -1 - - - - + 0 - RBX1A83A5F422C64C4A839C0EE03B906222 + RBXE5D68B9751CD41BBB8BF97D937744BA7 0 false @@ -585,12 +611,13 @@ AAAAU2NhbGVUeXBlAwAAAAQAAABTaXplCgAAAAA8AAAAAAAAADwAAAA=]]> - + 5 + .Hotbar 0 @@ -599,12 +626,13 @@ emUKAAAAAAAAAAAAAAAAPAAAAA==]]> -1 - + 1 + ::UIListLayout 0 @@ -615,12 +643,13 @@ aWdubWVudBURAAAAVmVydGljYWxBbGlnbm1lbnQAAAAA]]> - + 3 + .Container,.SearchBar 0 @@ -629,12 +658,13 @@ bnNwYXJlbmN5]]> -1 - + 2 + ::UIStroke 0 @@ -644,10 +674,11 @@ YWluZXJTdHJva2VUcmFuc3BhcmVuY3k=]]> - + 1 AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= + ::UICorner 0 @@ -657,12 +688,13 @@ YWluZXJTdHJva2VUcmFuc3BhcmVuY3k=]]> - + 2 + ::UIPadding 0 @@ -673,12 +705,13 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkU3VyZmFjZVBhZGRpbmc=]]> - + 3 + .Surface,.Hints,.Inventory 0 @@ -687,10 +720,11 @@ cmVuY3k=]]> -1 - + 1 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz + ::UICorner 0 @@ -700,12 +734,13 @@ cmVuY3k=]]> - + 2 + ::UIPadding 0 @@ -716,23 +751,12 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkU3VyZmFjZVBhZGRpbmc=]]> - - - 0 - null - - 0 - false - Derive from StyleSheet - -1 - - - - + 6 + .Hints 0 @@ -741,13 +765,14 @@ cmRlcgYAAAAAAADwvwQAAABTaXplCgAAgD8AAAAAAAAAAAAAAAA=]]> -1 - + 1 + ::UIListLayout 0 @@ -758,10 +783,11 @@ cnRpY2FsQWxpZ25tZW50FREAAABWZXJ0aWNhbEFsaWdubWVudAAAAAAFAAAAV3JhcHMDAQ==]]> - + 7 AQAAAAsAAABMYXlvdXRPcmRlcgYAAAAAAAAAAA== + .Inventory 0 @@ -770,10 +796,11 @@ cnRpY2FsQWxpZ25tZW50FREAAABWZXJ0aWNhbEFsaWdubWVudAAAAAAFAAAAV3JhcHMDAQ==]]>-1 - + 1 AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA + ::UIListLayout 0 @@ -783,7 +810,7 @@ cnRpY2FsQWxpZ25tZW50FREAAABWZXJ0aWNhbEFsaWdubWVudAAAAAAFAAAAV3JhcHMDAQ==]]> - + 1 + >ScrollingFrame 0 @@ -799,11 +827,12 @@ U2VsZWN0YWJsZQMABAAAAFNpemUKAACAPxIAAAAAAIA/AAAAAA==]]> -1 - + 2 + ::UIListLayout 0 @@ -815,12 +844,13 @@ CQAAAAAFAAAACQAAAFNvcnRPcmRlchUJAAAAU29ydE9yZGVyAgAAAAUAAABXcmFwcwMB]]> - + 8 + .Backpack 0 @@ -829,12 +859,13 @@ c2l0aW9uCgAAAD8AAAAAAACAPwAAAAA=]]> -1 - + 1 + ::UIListLayout 0 @@ -844,10 +875,11 @@ AABWZXJ0aWNhbEFsaWdubWVudBURAAAAVmVydGljYWxBbGlnbm1lbnQCAAAA]]> - + 2 AQAAAA0AAABQYWRkaW5nQm90dG9tCQAAAAAFAAAA + ::UIPadding 0 @@ -859,7 +891,7 @@ AABWZXJ0aWNhbEFsaWdubWVudBURAAAAVmVydGljYWxBbGlnbm1lbnQCAAAA]]> - + -1 - + 0 - RBX3FCD09B5CC5E49539C0DDCA0030578EE + RBX3FF93DD6DE164D53B39271179BB1AD31 0 false - Derive from DesignTokens + Derive from ThemeTokens -1 - + 0 false - DesignTokens + ThemeTokens -1 - + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= 0 @@ -938,10 +970,10 @@ Pw==]]> -1 - + 0 - RBX5386E31C9C0C4A45B50A17CA8B9D2965 + RBX1029A0A53F6C45CE84C5EAA5B9C031C3 0 false @@ -951,7 +983,7 @@ Pw==]]> - + -1 - + 0 - RBX5386E31C9C0C4A45B50A17CA8B9D2965 + RBX1029A0A53F6C45CE84C5EAA5B9C031C3 0 false @@ -986,229 +1018,5 @@ bmRDb2xvcg/NzMw+zczMPs3MzD4OAAAAVG9vbFRpcFBhZGRpbmcJAAAAAAIAAAA=]]> - - - - 0 - false - BaseStyleSheet - -1 - - - - - 0 - - Frame - - 0 - false - Frame - -1 - - - - - - 1 - - ScrollingFrame - - 0 - false - ScrollingFrame - -1 - - - - - - 2 - - TextLabel - - 0 - false - TextLabel - -1 - - - - - - 3 - - TextButton - - 0 - false - TextButton - -1 - - - - - - 4 - - TextBox - - 0 - false - TextBox - -1 - - - - - - 5 - - ImageButton - - 0 - false - ImageButton - -1 - - - - - - 6 - - ImageLabel - - 0 - false - ImageLabel - -1 - - - - - - 7 - - ViewportFrame - - 0 - false - ViewportFrame - -1 - - - - - - 8 - - VideoFrame - - 0 - false - VideoFrame - -1 - - - - - - 9 - - CanvasGroup - - 0 - false - CanvasGroup - -1 - - - - - - 10 - AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= - UIListLayout - - 0 - false - UIListLayout - -1 - - - - - - 11 - AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= - UIGridLayout - - 0 - false - UIGridLayout - -1 - - - - - - 12 - AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= - UIPageLayout - - 0 - false - UIPageLayout - -1 - - - - - - 13 - AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= - UITableLayout - - 0 - false - UITableLayout - -1 - - - - \ No newline at end of file diff --git a/src/Design/BaseTokens.model.json b/src/Design/BaseTokens.model.json deleted file mode 100644 index b0e03990..00000000 --- a/src/Design/BaseTokens.model.json +++ /dev/null @@ -1,106 +0,0 @@ -{ - "ClassName": "StyleSheet", - "Attributes": { - "ContainerBackgroundColor": "$BackgroundColor", - "ContainerBackgroundTransparency": 0.2, - "ContainerCornerRadius": "$SmallCornerRadius", - "ContainerStrokeColor": [ - 1, - 1, - 1 - ], - "ContainerStrokeTransparency": 0.8, - "HintFontFace": "$FontFace", - "HintTextColor": "$TextColor", - "HintTextSize": "$TextSize", - "SearchFontFace": "$FontFace", - "SearchPadding": { - "UDim": [ - 0, - 8 - ] - }, - "SearchPlaceholderColor": [ - 0.698039, - 0.698039, - 0.698039 - ], - "SearchTextColor": "$TextColor", - "SearchTextSize": "$TextSize", - "SearchTextStrokeTransparency": "$TextStrokeTransparency", - "SlotBackgroundColor": [ - 0.098039, - 0.105882, - 0.113725 - ], - "SlotBackgroundTransparency": 0.3, - "SlotCornerRadius": "$SmallCornerRadius", - "SlotEquipStrokeColor": [ - 1, - 1, - 1 - ], - "SlotEquipStrokeThickness": 4, - "SlotFontFace": "$FontFace", - "SlotIconCornerRadius": { - "UDim": [ - 0, - 0 - ] - }, - "SlotNumberFontFace": "$FontFace", - "SlotNumberStrokeColor": "$TextStrokeColor", - "SlotNumberStrokeTransparency": "$TextStrokeTransparency", - "SlotNumberTextColor": "$TextColor", - "SlotNumberTextSize": "$SmallTextSize", - "SlotPadding": { - "UDim": [ - 0, - 5 - ] - }, - "SlotPressStrokeColor": [ - 1, - 1, - 1 - ], - "SlotTextColor": "$TextColor", - "SlotTextSize": "$TextSize", - "SlotTextStrokeColor": "$TextStrokeColor", - "SlotTextStrokeTransparency": "$TextStrokeTransparency", - "SlotUnlockBackgroundColor": "$SlotBackgroundColor", - "StyleCategory": "Tokens", - "SurfaceBackgroundColor": "$BackgroundColor", - "SurfaceBackgroundTransparency": 0.3, - "SurfaceCornerRadius": "$CornerRadius", - "SurfacePadding": { - "UDim": [ - 0, - 5 - ] - }, - "ToolTipBackgroundColor": [ - 0.149019, - 0.156862, - 0.188235 - ], - "ToolTipBackgroundTranparency": 0, - "ToolTipCornerRadius": "$SmallCornerRadius", - "ToolTipFontFace": "$FontFace", - "ToolTipPadding": { - "UDim": [ - 0, - 4 - ] - }, - "ToolTipTextColor": "$TextColor", - "ToolTipTextSize": "$SmallTextSize" - }, - "Children": [ - { - "Name": "Derive from ThemeTokens", - "ClassName": "StyleDerive", - "Properties": {} - } - ] -} \ No newline at end of file diff --git a/src/Design/DefaultTheme.model.json b/src/Design/DefaultTheme.model.json deleted file mode 100644 index 9edcaee0..00000000 --- a/src/Design/DefaultTheme.model.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "ClassName": "StyleSheet", - "Attributes": { - "StyleCategory": "Themes" - }, - "Children": [ - { - "Name": "Derive from BaseTokens", - "ClassName": "StyleDerive", - "Properties": {} - } - ] -} \ No newline at end of file diff --git a/src/Design/LegacyTheme.model.json b/src/Design/LegacyTheme.model.json deleted file mode 100644 index 515b107f..00000000 --- a/src/Design/LegacyTheme.model.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "ClassName": "StyleSheet", - "Attributes": { - "ContainerBackgroundColor": [ - 0.368627, - 0.368627, - 0.368627 - ], - "ContainerStrokeTransparency": 1, - "CornerRadius": { - "UDim": [ - 0, - 0 - ] - }, - "FontFace": { - "family": "rbxasset://fonts/families/SourceSansPro.json", - "weight": "Regular", - "style": "Normal" - }, - "HintFontFace": { - "family": "rbxasset://fonts/families/SourceSansPro.json", - "weight": "Bold", - "style": "Normal" - }, - "HintTextSize": 24, - "SearchPadding": { - "UDim": [ - 0, - 0 - ] - }, - "SearchPlaceholderColor": [ - 1, - 1, - 1 - ], - "SearchTextSize": 24, - "SlotBackgroundColor": [ - 0.121568, - 0.121568, - 0.121568 - ], - "SlotEquipStrokeColor": [ - 0.352941, - 0.556862, - 0.913725 - ], - "SlotEquipStrokeThickness": 5, - "SlotPadding": { - "UDim": [ - 0, - 6 - ] - }, - "SlotUnlockBackgroundColor": [ - 0.192156, - 0.192156, - 0.192156 - ], - "SmallCornerRadius": { - "UDim": [ - 0, - 0 - ] - }, - "SmallTextSize": 14, - "StyleCategory": "Themes", - "TextSize": 14, - "TextStrokeTransparency": 1, - "ToolTipBackgroundColor": [ - 0.400000, - 0.400000, - 0.400000 - ], - "ToolTipPadding": { - "UDim": [ - 0, - 2 - ] - } - }, - "Children": [ - { - "Name": "Derive from BaseTokens", - "ClassName": "StyleDerive", - "Properties": {} - } - ] -} \ No newline at end of file diff --git a/src/Design/SatchelStyleSheet.model.json b/src/Design/SatchelStyleSheet.model.json deleted file mode 100644 index 35494afe..00000000 --- a/src/Design/SatchelStyleSheet.model.json +++ /dev/null @@ -1,511 +0,0 @@ -{ - "ClassName": "StyleSheet", - "Properties": {}, - "Children": [ - { - "Name": ".Hotbar", - "ClassName": "StyleRule", - "Properties": { - "Priority": 5, - "Selector": ".Hotbar" - }, - "Children": [ - { - "Name": "::UIListLayout", - "ClassName": "StyleRule", - "Properties": { - "Priority": 1, - "Selector": "::UIListLayout" - } - } - ] - }, - { - "Name": ".Hints", - "ClassName": "StyleRule", - "Properties": { - "Priority": 6, - "Selector": ".Hints" - }, - "Children": [ - { - "Name": "::UIListLayout", - "ClassName": "StyleRule", - "Properties": { - "Priority": 1, - "Selector": "::UIListLayout" - } - } - ] - }, - { - "Name": ".Backpack", - "ClassName": "StyleRule", - "Properties": { - "Priority": 8, - "Selector": ".Backpack" - }, - "Children": [ - { - "Name": "::UIPadding", - "ClassName": "StyleRule", - "Properties": { - "Priority": 2, - "Selector": "::UIPadding" - } - }, - { - "Name": "::UIListLayout", - "ClassName": "StyleRule", - "Properties": { - "Priority": 1, - "Selector": "::UIListLayout" - } - } - ] - }, - { - "Name": "ImageLabel", - "ClassName": "StyleRule", - "Properties": { - "Priority": 5, - "Selector": "ImageLabel" - }, - "Children": [ - { - "Name": ".HintSlot", - "ClassName": "StyleRule", - "Properties": { - "Priority": 1, - "Selector": ".HintSlot" - }, - "Children": [ - { - "Name": "::UIAspectRatioConstraint", - "ClassName": "StyleRule", - "Properties": { - "Priority": 1, - "Selector": "::UIAspectRatioConstraint" - } - } - ] - } - ] - }, - { - "Name": "Derive from DefaultTheme", - "ClassName": "StyleDerive", - "Properties": {} - }, - { - "Name": "TextBox", - "ClassName": "StyleRule", - "Properties": { - "Priority": 7, - "Selector": "TextBox" - }, - "Children": [ - { - "Name": ".SearchBar", - "ClassName": "StyleRule", - "Properties": { - "Priority": 2, - "Selector": ".SearchBar" - }, - "Children": [ - { - "Name": "::UIPadding", - "ClassName": "StyleRule", - "Properties": { - "Priority": 1, - "Selector": "::UIPadding" - } - }, - { - "Name": ">ImageButton", - "ClassName": "StyleRule", - "Properties": { - "Priority": 3, - "Selector": ">ImageButton" - }, - "Children": [ - { - "Name": "::UIAspectRatioConstraint", - "ClassName": "StyleRule", - "Properties": { - "Priority": 1, - "Selector": "::UIAspectRatioConstraint" - } - } - ] - } - ] - } - ] - }, - { - "Name": "ScrollingFrame", - "ClassName": "StyleRule", - "Properties": { - "Priority": 11, - "Selector": "ScrollingFrame" - } - }, - { - "Name": ".Surface,.Hints,.Inventory", - "ClassName": "StyleRule", - "Properties": { - "Priority": 3, - "Selector": ".Surface,.Hints,.Inventory" - }, - "Children": [ - { - "Name": "::UIPadding", - "ClassName": "StyleRule", - "Properties": { - "Priority": 2, - "Selector": "::UIPadding" - } - }, - { - "Name": "::UICorner", - "ClassName": "StyleRule", - "Properties": { - "Priority": 1, - "Selector": "::UICorner" - } - } - ] - }, - { - "Name": "ImageButton", - "ClassName": "StyleRule", - "Properties": { - "Priority": 6, - "Selector": "ImageButton" - } - }, - { - "Name": ".Inventory", - "ClassName": "StyleRule", - "Properties": { - "Priority": 7, - "Selector": ".Inventory" - }, - "Children": [ - { - "Name": ">ScrollingFrame", - "ClassName": "StyleRule", - "Properties": { - "Priority": 1, - "Selector": ">ScrollingFrame" - }, - "Children": [ - { - "Name": "::UIListLayout", - "ClassName": "StyleRule", - "Properties": { - "Priority": 2, - "Selector": "::UIListLayout" - } - } - ] - }, - { - "Name": "::UIListLayout", - "ClassName": "StyleRule", - "Properties": { - "Priority": 1, - "Selector": "::UIListLayout" - } - } - ] - }, - { - "Name": "Frame", - "ClassName": "StyleRule", - "Properties": { - "Priority": 12, - "Selector": "Frame" - }, - "Children": [ - { - "Name": ".Hint", - "ClassName": "StyleRule", - "Properties": { - "Priority": 2, - "Selector": ".Hint" - }, - "Children": [ - { - "Name": ">TextLabel", - "ClassName": "StyleRule", - "Properties": { - "Priority": 3, - "Selector": ">TextLabel" - } - }, - { - "Name": ">ImageLabel", - "ClassName": "StyleRule", - "Properties": { - "Priority": 4, - "Selector": ">ImageLabel" - }, - "Children": [ - { - "Name": "::UIAspectRatioConstraint", - "ClassName": "StyleRule", - "Properties": { - "Priority": 1, - "Selector": "::UIAspectRatioConstraint" - } - } - ] - } - ] - } - ] - }, - { - "Name": "TextLabel", - "ClassName": "StyleRule", - "Properties": { - "Priority": 10, - "Selector": "TextLabel" - }, - "Children": [ - { - "Name": ".Tooltip", - "ClassName": "StyleRule", - "Properties": { - "Priority": 9, - "Selector": ".Tooltip" - }, - "Children": [ - { - "Name": "::UIPadding", - "ClassName": "StyleRule", - "Properties": { - "Priority": 2, - "Selector": "::UIPadding" - } - }, - { - "Name": "::UICorner", - "ClassName": "StyleRule", - "Properties": { - "Priority": 1, - "Selector": "::UICorner" - } - } - ] - } - ] - }, - { - "Name": ".Container,.SearchBar", - "ClassName": "StyleRule", - "Properties": { - "Priority": 3, - "Selector": ".Container,.SearchBar" - }, - "Children": [ - { - "Name": "::UIStroke", - "ClassName": "StyleRule", - "Properties": { - "Priority": 2, - "Selector": "::UIStroke" - } - }, - { - "Name": "::UIPadding", - "ClassName": "StyleRule", - "Properties": { - "Priority": 2, - "Selector": "::UIPadding" - } - }, - { - "Name": "::UICorner", - "ClassName": "StyleRule", - "Properties": { - "Priority": 1, - "Selector": "::UICorner" - } - } - ] - }, - { - "Name": "TextButton", - "ClassName": "StyleRule", - "Properties": { - "Priority": 8, - "Selector": "TextButton" - }, - "Children": [ - { - "Name": ".Slot", - "ClassName": "StyleRule", - "Properties": { - "Priority": 2, - "Selector": ".Slot" - }, - "Children": [ - { - "Name": ">ImageLabel", - "ClassName": "StyleRule", - "Properties": { - "Priority": 7, - "Selector": ">ImageLabel" - }, - "Children": [ - { - "Name": "::UICorner", - "ClassName": "StyleRule", - "Properties": { - "Priority": 1, - "Selector": "::UICorner" - } - } - ] - }, - { - "Name": ":Press", - "ClassName": "StyleRule", - "Properties": { - "Priority": 9, - "Selector": ":Press" - }, - "Children": [ - { - "Name": ">.Tooltip", - "ClassName": "StyleRule", - "Properties": { - "Priority": 2, - "Selector": ">.Tooltip" - } - } - ] - }, - { - "Name": "::UIPadding", - "ClassName": "StyleRule", - "Properties": { - "Priority": 5, - "Selector": "::UIPadding" - } - }, - { - "Name": ".Unlocked", - "ClassName": "StyleRule", - "Properties": { - "Priority": 11, - "Selector": ".Unlocked" - }, - "Children": [ - { - "Name": ":Press", - "ClassName": "StyleRule", - "Properties": { - "Priority": 9, - "Selector": ":Press" - }, - "Children": [ - { - "Name": "::UIStroke", - "ClassName": "StyleRule", - "Properties": { - "Priority": 1, - "Selector": "::UIStroke" - } - } - ] - } - ] - }, - { - "Name": ":Hover", - "ClassName": "StyleRule", - "Properties": { - "Priority": 8, - "Selector": ":Hover" - }, - "Children": [ - { - "Name": ">.Tooltip", - "ClassName": "StyleRule", - "Properties": { - "Priority": 1, - "Selector": ">.Tooltip" - } - } - ] - }, - { - "Name": ">TextLabel", - "ClassName": "StyleRule", - "Properties": { - "Priority": 4, - "Selector": ">TextLabel" - }, - "Children": [ - { - "Name": ".Tooltip", - "ClassName": "StyleRule", - "Properties": { - "Priority": 9, - "Selector": ".Tooltip" - } - }, - { - "Name": ".SlotNumber", - "ClassName": "StyleRule", - "Properties": { - "Priority": 1, - "Selector": ".SlotNumber" - } - } - ] - }, - { - "Name": "::UICorner", - "ClassName": "StyleRule", - "Properties": { - "Priority": 1, - "Selector": "::UICorner" - } - }, - { - "Name": ".Equipped", - "ClassName": "StyleRule", - "Properties": { - "Priority": 10, - "Selector": ".Equipped" - }, - "Children": [ - { - "Name": "::UIStroke", - "ClassName": "StyleRule", - "Properties": { - "Priority": 1, - "Selector": "::UIStroke" - } - } - ] - }, - { - "Name": "::UITextSizeConstraint", - "ClassName": "StyleRule", - "Properties": { - "Priority": 6, - "Selector": "::UITextSizeConstraint" - } - } - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/src/Design/ThemeTokens.model.json b/src/Design/ThemeTokens.model.json deleted file mode 100644 index 9edcaee0..00000000 --- a/src/Design/ThemeTokens.model.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "ClassName": "StyleSheet", - "Attributes": { - "StyleCategory": "Themes" - }, - "Children": [ - { - "Name": "Derive from BaseTokens", - "ClassName": "StyleDerive", - "Properties": {} - } - ] -} \ No newline at end of file From 8c3b8ca00cdddccf5decd322badb5ea179f8de27 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 20 Feb 2026 14:39:25 -0800 Subject: [PATCH 017/186] Update hints frame Signed-off-by: Ryan Luu --- .gitignore | 1 + src/Design.rbxmx | 1093 +++++++++++++++++++++++----------------------- 2 files changed, 548 insertions(+), 546 deletions(-) diff --git a/.gitignore b/.gitignore index ac03bdf3..a8765c27 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ sourcemap.json *.rbxlx *.rbxm *.rbxmx +!src/ # Wally Packages/ diff --git a/src/Design.rbxmx b/src/Design.rbxmx index 7f80862f..dd079b31 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,170 +11,155 @@ -1 - + - + 0 false - SatchelStyleSheet + ThemeTokens + -1 + + + + + + + 0 + false + LegacyTheme -1 - + - 12 - AAAAAA== - - Frame + 0 + RBXA8178370153F478B9B12E6598F085157 0 false - Frame + Derive from BaseTokens -1 - - - 2 - - - .Hint - - 0 - false - .Hint - -1 - - - - - 3 - - - >TextLabel - - 0 - false - >TextLabel - -1 - - - - - - 4 - - - >ImageLabel - - 0 - false - >ImageLabel - -1 - - - - - 1 - AAAAAA== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - - - + + + + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= + 0 + false + DefaultTheme + -1 + + + - 11 - AAAAAA== - - ScrollingFrame + 0 + RBXA8178370153F478B9B12E6598F085157 0 false - ScrollingFrame + Derive from BaseTokens -1 - + + + + + 0 + false + BaseTokens + -1 + + + - 10 - AAAAAA== - - TextLabel + 0 + RBX68E8F4AB849D40F6BF3DC148319A05B7 0 false - TextLabel + Derive from ThemeTokens + -1 + + + + + + + + 0 + false + SatchelStyleSheet + -1 + + + + + 0 + RBX5904AEDE67814AE7A33FBBBB90C2112D + + 0 + false + Derive from DefaultTheme -1 - - - 9 - - - .Tooltip - - 0 - false - .Tooltip - -1 - - - - - 1 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - - - 2 - - - ::UIPadding - - 0 - false - ::UIPadding - -1 - - - - - + 8 AAAAAA== @@ -187,7 +172,7 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkVG9vbFRpcFBhZGRpbmc=]]> -1 - + 2 -1 - + - 10 + 9 AAAAAA== - .Equipped + :Press 0 false - .Equipped + :Press -1 - + - 1 - + 2 + AQAAAAcAAABWaXNpYmxlAwE= - ::UIStroke + >.Tooltip 0 false - ::UIStroke + >.Tooltip -1 - + - 8 + 10 AAAAAA== - :Hover + .Equipped 0 false - :Hover + .Equipped -1 - + 1 - AQAAAAcAAABWaXNpYmxlAwE= + - >.Tooltip + ::UIStroke 0 false - >.Tooltip + ::UIStroke -1 - + - 7 - + 11 + - >ImageLabel + .Unlocked 0 false - >ImageLabel + .Unlocked -1 - + - 1 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== + 9 + AAAAAA== - ::UICorner + :Press 0 false - ::UICorner + :Press -1 + + + 1 + + + ::UIStroke + + 0 + false + ::UIStroke + -1 + + + - - - 6 - - - ::UITextSizeConstraint - - 0 - false - ::UITextSizeConstraint - -1 - - - - - - 5 - - - ::UIPadding - - 0 - false - ::UIPadding - -1 - - - - + 4 AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= @@ -338,7 +307,28 @@ YWRkaW5nVG9wAgwAAAAkU2xvdFBhZGRpbmc=]]> -1 - + + + 1 + + + .SlotNumber + + 0 + false + .SlotNumber + -1 + + + + 9 AQAAAAcAAABWaXNpYmxlAwA= @@ -352,29 +342,52 @@ YWRkaW5nVG9wAgwAAAAkU2xvdFBhZGRpbmc=]]> - + + + + 8 + AAAAAA== + + :Hover + + 0 + false + :Hover + -1 + + + 1 - + AQAAAAcAAABWaXNpYmxlAwE= - .SlotNumber + >.Tooltip 0 false - .SlotNumber + >.Tooltip -1 - + + + 5 + + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + + 1 AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz @@ -388,73 +401,45 @@ AAAAAEA=]]> - + - 11 - + 6 + - .Unlocked + ::UITextSizeConstraint 0 false - .Unlocked + ::UITextSizeConstraint -1 - - - 9 - AAAAAA== - - :Press - - 0 - false - :Press - -1 - - - - - 1 - - - ::UIStroke - - 0 - false - ::UIStroke - -1 - - - - - + - 9 - AAAAAA== + 7 + - :Press + >ImageLabel 0 false - :Press + >ImageLabel -1 - + - 2 - AQAAAAcAAABWaXNpYmxlAwE= + 1 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== - >.Tooltip + ::UICorner 0 false - >.Tooltip + ::UICorner -1 @@ -462,70 +447,66 @@ b3ICFQAAACRTbG90UHJlc3NTdHJva2VDb2xvcgkAAABUaGlja25lc3MGAAAAAAAAAEA=]]> - + - 7 + 12 AAAAAA== - TextBox + Frame 0 false - TextBox + Frame -1 - + 2 - + - .SearchBar + .Hint 0 false - .SearchBar + .Hint -1 - + - 1 - + 3 + - ::UIPadding + >TextLabel 0 false - ::UIPadding + >TextLabel -1 - + - 3 - + 4 + - >ImageButton + >ImageLabel 0 false - >ImageButton + >ImageLabel -1 - + 1 AAAAAA== @@ -542,76 +523,69 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAAcAAABWaXNpYmxlAwA=]]> - - - 6 - AAAAAA== - - ImageButton - - 0 - false - ImageButton - -1 - - - - + - 5 - AAAAAA== + 3 + - ImageLabel + .Container,.SearchBar 0 false - ImageLabel + .Container,.SearchBar -1 - + + + 2 + + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + + + + 2 + + + ::UIStroke + + 0 + false + ::UIStroke + -1 + + + + 1 - + AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= - .HintSlot + ::UICorner 0 false - .HintSlot + ::UICorner -1 - - - 1 - AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - - - 0 - RBXE5D68B9751CD41BBB8BF97D937744BA7 - - 0 - false - Derive from DefaultTheme - -1 - - - - + 5 -1 - + 1 - + 3 - + - .Container,.SearchBar + .Surface,.Inventory 0 false - .Container,.SearchBar + .Surface,.Inventory -1 - + - 2 - + 1 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz - ::UIStroke + ::UICorner 0 false - ::UIStroke + ::UICorner -1 - + - 1 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= + 2 + - ::UICorner + ::UIPadding 0 false - ::UICorner + ::UIPadding -1 - + + + + 7 + AAAAAA== + + TextBox + + 0 + false + TextBox + -1 + + + 2 - + - ::UIPadding + .SearchBar 0 false - ::UIPadding + .SearchBar -1 + + + 1 + + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + + + + 3 + + + >ImageButton + + 0 + false + >ImageButton + -1 + + + + + 1 + AAAAAA== + + ::UIAspectRatioConstraint + + 0 + false + ::UIAspectRatioConstraint + -1 + + + + - + + + 6 + AAAAAA== + + ImageButton + + 0 + false + ImageButton + -1 + + + + + + 11 + AAAAAA== + + ScrollingFrame + + 0 + false + ScrollingFrame + -1 + + + + - 3 - + 8 + - .Surface,.Hints,.Inventory + .Backpack 0 false - .Surface,.Hints,.Inventory + .Backpack -1 - - - 1 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - + 2 - + AQAAAA0AAABQYWRkaW5nQm90dG9tCQAAAAAFAAAA ::UIPadding @@ -750,28 +800,12 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkU3VyZmFjZVBhZGRpbmc=]]> - - - - 6 - - - .Hints - - 0 - false - .Hints - -1 - - - + 1 - + ::UIListLayout @@ -783,7 +817,7 @@ cnRpY2FsQWxpZ25tZW50FREAAABWZXJ0aWNhbEFsaWdubWVudAAAAAAFAAAAV3JhcHMDAQ==]]> - + 7 AQAAAAsAAABMYXlvdXRPcmRlcgYAAAAAAAAAAA== @@ -796,7 +830,7 @@ cnRpY2FsQWxpZ25tZW50FREAAABWZXJ0aWNhbEFsaWdubWVudAAAAAAFAAAAV3JhcHMDAQ==]]>-1 - + 1 AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA @@ -810,7 +844,7 @@ cnRpY2FsQWxpZ25tZW50FREAAABWZXJ0aWNhbEFsaWdubWVudAAAAAAFAAAAV3JhcHMDAQ==]]> - + 1 -1 - + 2 - + - 8 - + 6 + - .Backpack + .Hints 0 false - .Backpack + .Hints -1 - + 1 - + ::UIListLayout @@ -875,147 +910,113 @@ AABWZXJ0aWNhbEFsaWdubWVudBURAAAAVmVydGljYWxBbGlnbm1lbnQCAAAA]]> - + + + + 10 + AAAAAA== + + TextLabel + + 0 + false + TextLabel + -1 + + + - 2 - AQAAAA0AAABQYWRkaW5nQm90dG9tCQAAAAAFAAAA + 9 + - ::UIPadding + .Tooltip 0 false - ::UIPadding + .Tooltip -1 + + + 2 + + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + + + + 1 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz + + ::UICorner + + 0 + false + ::UICorner + -1 + + + - - - - - 0 - false - BaseTokens - -1 - - - - - 0 - RBX3FF93DD6DE164D53B39271179BB1AD31 - - 0 - false - Derive from ThemeTokens - -1 - - - - - - - - 0 - false - ThemeTokens - -1 - - - - - - AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= - 0 - false - DefaultTheme - -1 - - - - - 0 - RBX1029A0A53F6C45CE84C5EAA5B9C031C3 - - 0 - false - Derive from BaseTokens - -1 - - - - - - - - 0 - false - LegacyTheme - -1 - - - + - 0 - RBX1029A0A53F6C45CE84C5EAA5B9C031C3 + 5 + AAAAAA== + + ImageLabel 0 false - Derive from BaseTokens + ImageLabel -1 + + + 1 + + + .HintSlot + + 0 + false + .HintSlot + -1 + + + + + 1 + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== + + ::UIAspectRatioConstraint + + 0 + false + ::UIAspectRatioConstraint + -1 + + + + From 047e637520eb561bb3ffa065145a53629ac4343e Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 21 Feb 2026 02:28:42 -0800 Subject: [PATCH 018/186] Don't return nil Signed-off-by: Ryan Luu --- src/Components/Tooltip.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Tooltip.luau b/src/Components/Tooltip.luau index d8fc3aa4..860b56d6 100644 --- a/src/Components/Tooltip.luau +++ b/src/Components/Tooltip.luau @@ -7,7 +7,7 @@ export type Props = { local function Tooltip(props: Props) -- Hide tooltip if there is no text if not props.text or props.text == "" then - return nil + return end return React.createElement("TextLabel", { From 7f8f82af7abad41faa252f7665f521e82e82b47d Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 21 Feb 2026 02:51:06 -0800 Subject: [PATCH 019/186] Add number hint logic Signed-off-by: Ryan Luu --- src/Components/HotbarHint.luau | 2 +- src/Components/Slot.luau | 8 ++++---- src/Components/Slot.story.luau | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Components/HotbarHint.luau b/src/Components/HotbarHint.luau index 6e1c6e74..bab539e8 100644 --- a/src/Components/HotbarHint.luau +++ b/src/Components/HotbarHint.luau @@ -35,7 +35,7 @@ local function HotbarHint(props: Props) end end, {}) - local visible = props.forceVisible == true or isGamepadPreferred + local visible = props.forceVisible or isGamepadPreferred return React.createElement("ImageLabel", { Image = UserInputService:GetImageForKeyCode(props.hintKey), diff --git a/src/Components/Slot.luau b/src/Components/Slot.luau index 89f9153c..f1bc8220 100644 --- a/src/Components/Slot.luau +++ b/src/Components/Slot.luau @@ -10,7 +10,7 @@ export type Props = { tool: Tool?, slotNumber: number?, equipped: boolean?, - forceVisible: boolean?, + forceHintVisible: boolean?, unlocked: boolean?, order: number?, onActivated: (() -> ())?, @@ -21,7 +21,7 @@ local function Slot(props: Props) local toolImage = props.tool and props.tool.TextureId local tooltipText = props.tool and props.tool.ToolTip - -- Only show hint if keyboard and mouse is preferred or forced visible + -- Only show slot number if keyboard and mouse is preferred or forced visible local isKeyboardAndMousePreferred, setIsKeyboardAndMousePreferred = React.useState(UserInputService.PreferredInput == Enum.PreferredInput.KeyboardAndMouse) @@ -45,7 +45,7 @@ local function Slot(props: Props) end end, {}) - local visible = props.forceVisible == true or isKeyboardAndMousePreferred + local hintVisible = props.forceHintVisible or isKeyboardAndMousePreferred -- Generate tags based on state local tags = "Slot" @@ -65,12 +65,12 @@ local function Slot(props: Props) return React.createElement("TextButton", { Text = slotText, LayoutOrder = props.order, - Visible = visible, [React.Tag] = tags, [React.Event.Activated] = props.onActivated, }, { NumberHint = React.createElement("TextLabel", { Text = props.slotNumber or 0, + Visible = hintVisible, [React.Tag] = "SlotNumber", }), TextureIcon = React.createElement("ImageLabel", { diff --git a/src/Components/Slot.story.luau b/src/Components/Slot.story.luau index 4feb6a60..c369c26e 100644 --- a/src/Components/Slot.story.luau +++ b/src/Components/Slot.story.luau @@ -9,7 +9,7 @@ local controls = { tooltipText = "A classic sword", equipped = false, unlocked = false, - forceNumberVisible = true, + forceHintVisible = true, } type Props = { @@ -30,7 +30,7 @@ return { slotNumber = props.controls.slotNumber, equipped = props.controls.equipped, unlocked = props.controls.unlocked, - forceVisible = props.controls.forceNumberVisible, + forceHintVisible = props.controls.forceHintVisible, }) end, } From 912d0fc5eb9972b8de0a3c8bdef24a66ba9f3035 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 21 Feb 2026 03:06:41 -0800 Subject: [PATCH 020/186] Improve getting tool properties Signed-off-by: Ryan Luu --- src/Components/Slot.luau | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Components/Slot.luau b/src/Components/Slot.luau index f1bc8220..3828d4b4 100644 --- a/src/Components/Slot.luau +++ b/src/Components/Slot.luau @@ -17,9 +17,10 @@ export type Props = { } local function Slot(props: Props) - local toolName = props.tool and props.tool.Name - local toolImage = props.tool and props.tool.TextureId - local tooltipText = props.tool and props.tool.ToolTip + local tool = props.tool + local toolName = tool and tool.Name + local toolImage = tool and tool.TextureId + local tooltipText = tool and tool.ToolTip -- Only show slot number if keyboard and mouse is preferred or forced visible local isKeyboardAndMousePreferred, setIsKeyboardAndMousePreferred = From 2e1d67ab5b07ce46570219eb7a638989a08d3e01 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 21 Feb 2026 03:19:07 -0800 Subject: [PATCH 021/186] Combine order and number hint props Signed-off-by: Ryan Luu --- src/Components/Slot.luau | 14 +++++++++++--- src/Components/Slot.story.luau | 4 ++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Components/Slot.luau b/src/Components/Slot.luau index 3828d4b4..599ad121 100644 --- a/src/Components/Slot.luau +++ b/src/Components/Slot.luau @@ -8,10 +8,9 @@ local Tooltip = require(script.Parent.Tooltip) export type Props = { tool: Tool?, - slotNumber: number?, equipped: boolean?, - forceHintVisible: boolean?, unlocked: boolean?, + forceHintVisible: boolean?, order: number?, onActivated: (() -> ())?, } @@ -22,6 +21,15 @@ local function Slot(props: Props) local toolImage = tool and tool.TextureId local tooltipText = tool and tool.ToolTip + -- Only show numbers 1-10 for hints and show 0 for the 10th slot + local order = props.order or 1 + local slotNumber = "" + if order >= 1 and order < 10 then + slotNumber = tostring(order) + elseif order == 10 then + slotNumber = "0" + end + -- Only show slot number if keyboard and mouse is preferred or forced visible local isKeyboardAndMousePreferred, setIsKeyboardAndMousePreferred = React.useState(UserInputService.PreferredInput == Enum.PreferredInput.KeyboardAndMouse) @@ -70,7 +78,7 @@ local function Slot(props: Props) [React.Event.Activated] = props.onActivated, }, { NumberHint = React.createElement("TextLabel", { - Text = props.slotNumber or 0, + Text = slotNumber, Visible = hintVisible, [React.Tag] = "SlotNumber", }), diff --git a/src/Components/Slot.story.luau b/src/Components/Slot.story.luau index c369c26e..d7d1abd1 100644 --- a/src/Components/Slot.story.luau +++ b/src/Components/Slot.story.luau @@ -4,11 +4,11 @@ local Slot = require(script.Parent.Slot) local controls = { toolName = "Sword", - slotNumber = 9, toolImage = "rbxasset://Textures/Sword128.png", tooltipText = "A classic sword", equipped = false, unlocked = false, + order = 1, forceHintVisible = true, } @@ -27,9 +27,9 @@ return { return React.createElement(Slot, { tool = Tool, - slotNumber = props.controls.slotNumber, equipped = props.controls.equipped, unlocked = props.controls.unlocked, + order = props.controls.order, forceHintVisible = props.controls.forceHintVisible, }) end, From 3d3f779f3e0a5e1092cf7c2f7e420cb0f177763b Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 21 Feb 2026 03:24:42 -0800 Subject: [PATCH 022/186] Rename hintKey prop to key Signed-off-by: Ryan Luu --- src/Components/Hotbar.luau | 4 ++-- src/Components/HotbarHint.luau | 4 ++-- src/Components/HotbarHint.story.luau | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Components/Hotbar.luau b/src/Components/Hotbar.luau index be0f8c2b..205f1061 100644 --- a/src/Components/Hotbar.luau +++ b/src/Components/Hotbar.luau @@ -12,12 +12,12 @@ local function Hotbar(props: Props) }, { -- Create default hints for switching between hotbar slots SlotLeftHint = React.createElement(HotbarHint, { - hintKey = Enum.KeyCode.ButtonL1, + key = Enum.KeyCode.ButtonL1, forceVisible = props.forceHintVisible, order = -1, }), SlotRightHint = React.createElement(HotbarHint, { - hintKey = Enum.KeyCode.ButtonR1, + key = Enum.KeyCode.ButtonR1, forceVisible = props.forceHintVisible, order = 100, }), diff --git a/src/Components/HotbarHint.luau b/src/Components/HotbarHint.luau index bab539e8..6eb70d0b 100644 --- a/src/Components/HotbarHint.luau +++ b/src/Components/HotbarHint.luau @@ -5,7 +5,7 @@ local UserInputService = game:GetService("UserInputService") local React = require(script.Parent.Parent.Parent.react) export type Props = { - hintKey: Enum.KeyCode, + key: Enum.KeyCode, forceVisible: boolean?, order: number?, } @@ -38,7 +38,7 @@ local function HotbarHint(props: Props) local visible = props.forceVisible or isGamepadPreferred return React.createElement("ImageLabel", { - Image = UserInputService:GetImageForKeyCode(props.hintKey), + Image = UserInputService:GetImageForKeyCode(props.key), LayoutOrder = props.order, Visible = visible, [React.Tag] = "HintSlot", diff --git a/src/Components/HotbarHint.story.luau b/src/Components/HotbarHint.story.luau index 405b2fd1..0df793e1 100644 --- a/src/Components/HotbarHint.story.luau +++ b/src/Components/HotbarHint.story.luau @@ -15,7 +15,7 @@ return { controls = controls, story = function(props: Props) return React.createElement(HotbarHint, { - hintKey = Enum.KeyCode.ButtonX, + key = Enum.KeyCode.ButtonX, forceVisible = props.controls.forceVisible, }) end, From 67f079c9756f8f964fd31108ed79e29756d2d87b Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 21 Feb 2026 03:31:14 -0800 Subject: [PATCH 023/186] Add logic for slot amount Signed-off-by: Ryan Luu --- src/Components/Hotbar.luau | 25 ++++++++++++++++++++----- src/Components/Hotbar.story.luau | 24 +++++------------------- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/Components/Hotbar.luau b/src/Components/Hotbar.luau index 205f1061..d42fa278 100644 --- a/src/Components/Hotbar.luau +++ b/src/Components/Hotbar.luau @@ -1,16 +1,19 @@ local React = require(script.Parent.Parent.Parent.react) local HotbarHint = require(script.Parent.HotbarHint) +local Slot = require(script.Parent.Slot) export type Props = { forceHintVisible: boolean?, + slots: number?, + unlocked: boolean?, } local function Hotbar(props: Props) - return React.createElement("Frame", { - [React.Tag] = "Hotbar", - }, { - -- Create default hints for switching between hotbar slots + local slotCount = props.slots or 10 + + local children = { + -- Create default hints for equipping between hotbar slots SlotLeftHint = React.createElement(HotbarHint, { key = Enum.KeyCode.ButtonL1, forceVisible = props.forceHintVisible, @@ -21,7 +24,19 @@ local function Hotbar(props: Props) forceVisible = props.forceHintVisible, order = 100, }), - }) + } + + for slotNumber = 1, slotCount do + children[slotNumber] = React.createElement(Slot, { + order = slotNumber, + forceNumberVisible = props.forceHintVisible, + unlocked = props.unlocked, + }) + end + + return React.createElement("Frame", { + [React.Tag] = "Hotbar", + }, children) end return Hotbar diff --git a/src/Components/Hotbar.story.luau b/src/Components/Hotbar.story.luau index e3fac614..d4904af8 100644 --- a/src/Components/Hotbar.story.luau +++ b/src/Components/Hotbar.story.luau @@ -1,14 +1,11 @@ local React = require(script.Parent.Parent.Parent.react) local Hotbar = require(script.Parent.Hotbar) -local Slot = require(script.Parent.Slot) local controls = { forceHintVisible = true, - toolName = "Sword", - slotNumber = 9, - toolImage = "rbxasset://Textures/Sword128.png", - tooltipText = "A classic sword", + slots = 10, + unlocked = false, } type Props = { @@ -19,21 +16,10 @@ return { summary = "Hotbar component that holds hotbar slots and hints", controls = controls, story = function(props: Props) - local Tool = Instance.new("Tool") - Tool.Name = props.controls.toolName - Tool.TextureId = props.controls.toolImage - Tool.ToolTip = props.controls.tooltipText - - local component = React.createElement(Hotbar, { + return React.createElement(Hotbar, { forceHintVisible = props.controls.forceHintVisible, - }, { - Tool = React.createElement(Slot, { - tool = Tool, - slotNumber = 1, - order = 1, - }), + slots = props.controls.slots, + unlocked = props.controls.unlocked, }) - - return component end, } From 5ac19951ce83cc2badbb0453d01ee47048433af0 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 21 Feb 2026 03:31:51 -0800 Subject: [PATCH 024/186] Fix using key prop Signed-off-by: Ryan Luu --- src/Components/Hotbar.luau | 4 ++-- src/Components/HotbarHint.luau | 4 ++-- src/Components/HotbarHint.story.luau | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Components/Hotbar.luau b/src/Components/Hotbar.luau index d42fa278..a8c62acd 100644 --- a/src/Components/Hotbar.luau +++ b/src/Components/Hotbar.luau @@ -15,12 +15,12 @@ local function Hotbar(props: Props) local children = { -- Create default hints for equipping between hotbar slots SlotLeftHint = React.createElement(HotbarHint, { - key = Enum.KeyCode.ButtonL1, + keyCode = Enum.KeyCode.ButtonL1, forceVisible = props.forceHintVisible, order = -1, }), SlotRightHint = React.createElement(HotbarHint, { - key = Enum.KeyCode.ButtonR1, + keyCode = Enum.KeyCode.ButtonR1, forceVisible = props.forceHintVisible, order = 100, }), diff --git a/src/Components/HotbarHint.luau b/src/Components/HotbarHint.luau index 6eb70d0b..6f155e12 100644 --- a/src/Components/HotbarHint.luau +++ b/src/Components/HotbarHint.luau @@ -5,7 +5,7 @@ local UserInputService = game:GetService("UserInputService") local React = require(script.Parent.Parent.Parent.react) export type Props = { - key: Enum.KeyCode, + keyCode: Enum.KeyCode, forceVisible: boolean?, order: number?, } @@ -38,7 +38,7 @@ local function HotbarHint(props: Props) local visible = props.forceVisible or isGamepadPreferred return React.createElement("ImageLabel", { - Image = UserInputService:GetImageForKeyCode(props.key), + Image = UserInputService:GetImageForKeyCode(props.keyCode), LayoutOrder = props.order, Visible = visible, [React.Tag] = "HintSlot", diff --git a/src/Components/HotbarHint.story.luau b/src/Components/HotbarHint.story.luau index 0df793e1..6105f724 100644 --- a/src/Components/HotbarHint.story.luau +++ b/src/Components/HotbarHint.story.luau @@ -15,7 +15,7 @@ return { controls = controls, story = function(props: Props) return React.createElement(HotbarHint, { - key = Enum.KeyCode.ButtonX, + keyCode = Enum.KeyCode.ButtonX, forceVisible = props.controls.forceVisible, }) end, From dfa65274ff9549d322f7e31944479bd1e7fd68f3 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 21 Feb 2026 03:37:19 -0800 Subject: [PATCH 025/186] Shorten preferred input name Signed-off-by: Ryan Luu --- src/Components/Slot.luau | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Components/Slot.luau b/src/Components/Slot.luau index 599ad121..e784d096 100644 --- a/src/Components/Slot.luau +++ b/src/Components/Slot.luau @@ -31,7 +31,7 @@ local function Slot(props: Props) end -- Only show slot number if keyboard and mouse is preferred or forced visible - local isKeyboardAndMousePreferred, setIsKeyboardAndMousePreferred = + local isKeyboardPreferred, setIsKeyboardPreferred = React.useState(UserInputService.PreferredInput == Enum.PreferredInput.KeyboardAndMouse) React.useEffect(function() @@ -39,9 +39,9 @@ local function Slot(props: Props) local preferredInput = UserInputService.PreferredInput if preferredInput == Enum.PreferredInput.KeyboardAndMouse then - setIsKeyboardAndMousePreferred(true) + setIsKeyboardPreferred(true) else - setIsKeyboardAndMousePreferred(false) + setIsKeyboardPreferred(false) end end @@ -54,7 +54,7 @@ local function Slot(props: Props) end end, {}) - local hintVisible = props.forceHintVisible or isKeyboardAndMousePreferred + local hintVisible = props.forceHintVisible or isKeyboardPreferred -- Generate tags based on state local tags = "Slot" From c62540c38050671f1831d90d91ead8b7c60636f7 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 21 Feb 2026 03:39:35 -0800 Subject: [PATCH 026/186] Separate gamepad and keyboard hint forcing Signed-off-by: Ryan Luu --- src/Components/Hotbar.luau | 9 +++++---- src/Components/Hotbar.story.luau | 6 ++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Components/Hotbar.luau b/src/Components/Hotbar.luau index a8c62acd..c6a75dea 100644 --- a/src/Components/Hotbar.luau +++ b/src/Components/Hotbar.luau @@ -4,7 +4,8 @@ local HotbarHint = require(script.Parent.HotbarHint) local Slot = require(script.Parent.Slot) export type Props = { - forceHintVisible: boolean?, + forceGamepadHintVisible: boolean?, + forceKeyboardHintVisible: boolean?, slots: number?, unlocked: boolean?, } @@ -16,12 +17,12 @@ local function Hotbar(props: Props) -- Create default hints for equipping between hotbar slots SlotLeftHint = React.createElement(HotbarHint, { keyCode = Enum.KeyCode.ButtonL1, - forceVisible = props.forceHintVisible, + forceVisible = props.forceGamepadHintVisible, order = -1, }), SlotRightHint = React.createElement(HotbarHint, { keyCode = Enum.KeyCode.ButtonR1, - forceVisible = props.forceHintVisible, + forceVisible = props.forceGamepadHintVisible, order = 100, }), } @@ -29,7 +30,7 @@ local function Hotbar(props: Props) for slotNumber = 1, slotCount do children[slotNumber] = React.createElement(Slot, { order = slotNumber, - forceNumberVisible = props.forceHintVisible, + forceNumberVisible = props.forceKeyboardHintVisible, unlocked = props.unlocked, }) end diff --git a/src/Components/Hotbar.story.luau b/src/Components/Hotbar.story.luau index d4904af8..86ab5244 100644 --- a/src/Components/Hotbar.story.luau +++ b/src/Components/Hotbar.story.luau @@ -3,7 +3,8 @@ local React = require(script.Parent.Parent.Parent.react) local Hotbar = require(script.Parent.Hotbar) local controls = { - forceHintVisible = true, + forceGamepadHintVisible = true, + forceKeyboardHintVisible = true, slots = 10, unlocked = false, } @@ -17,7 +18,8 @@ return { controls = controls, story = function(props: Props) return React.createElement(Hotbar, { - forceHintVisible = props.controls.forceHintVisible, + forceGamepadHintVisible = props.controls.forceGamepadHintVisible, + forceKeyboardHintVisible = props.controls.forceKeyboardHintVisible, slots = props.controls.slots, unlocked = props.controls.unlocked, }) From 4c2c5822f32f395cee14d244ca107c807ede9871 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 21 Feb 2026 04:17:28 -0800 Subject: [PATCH 027/186] Add opening inventory logic for hotbar Signed-off-by: Ryan Luu --- src/Components/Hotbar.luau | 35 +++++++++++++++++++++----------- src/Components/Hotbar.story.luau | 15 ++++++++++++++ 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/Components/Hotbar.luau b/src/Components/Hotbar.luau index c6a75dea..ec424e5c 100644 --- a/src/Components/Hotbar.luau +++ b/src/Components/Hotbar.luau @@ -7,31 +7,42 @@ export type Props = { forceGamepadHintVisible: boolean?, forceKeyboardHintVisible: boolean?, slots: number?, + tools: { Tool? }?, unlocked: boolean?, + opened: boolean?, } local function Hotbar(props: Props) local slotCount = props.slots or 10 - local children = { + local children = {} + + for slotNumber = 1, slotCount do + local tool = props.tools and props.tools[slotNumber] + local slotUnlocked = props.unlocked and tool ~= nil + + -- Only show slots if the hotbar is opened or if there is a tool in the slot + if props.opened or tool then + children[slotNumber] = React.createElement(Slot, { + order = slotNumber, + tool = tool, + forceNumberVisible = props.forceKeyboardHintVisible, + unlocked = slotUnlocked, + }) + end + end + + if next(children) then -- Create default hints for equipping between hotbar slots - SlotLeftHint = React.createElement(HotbarHint, { + children.SlotLeftHint = React.createElement(HotbarHint, { keyCode = Enum.KeyCode.ButtonL1, forceVisible = props.forceGamepadHintVisible, order = -1, - }), - SlotRightHint = React.createElement(HotbarHint, { + }) + children.SlotRightHint = React.createElement(HotbarHint, { keyCode = Enum.KeyCode.ButtonR1, forceVisible = props.forceGamepadHintVisible, order = 100, - }), - } - - for slotNumber = 1, slotCount do - children[slotNumber] = React.createElement(Slot, { - order = slotNumber, - forceNumberVisible = props.forceKeyboardHintVisible, - unlocked = props.unlocked, }) end diff --git a/src/Components/Hotbar.story.luau b/src/Components/Hotbar.story.luau index 86ab5244..bb71b62a 100644 --- a/src/Components/Hotbar.story.luau +++ b/src/Components/Hotbar.story.luau @@ -6,7 +6,12 @@ local controls = { forceGamepadHintVisible = true, forceKeyboardHintVisible = true, slots = 10, + toolName = "Sword", + toolImage = "rbxasset://Textures/Sword128.png", + tooltipText = "A classic sword", + toolSlot = 1, unlocked = false, + opened = true, } type Props = { @@ -17,11 +22,21 @@ return { summary = "Hotbar component that holds hotbar slots and hints", controls = controls, story = function(props: Props) + local tool = Instance.new("Tool") + tool.Name = props.controls.toolName + tool.TextureId = props.controls.toolImage + tool.ToolTip = props.controls.tooltipText + + local tools = {} + tools[props.controls.toolSlot] = tool + return React.createElement(Hotbar, { forceGamepadHintVisible = props.controls.forceGamepadHintVisible, forceKeyboardHintVisible = props.controls.forceKeyboardHintVisible, slots = props.controls.slots, + tools = tools, unlocked = props.controls.unlocked, + opened = props.controls.opened, }) end, } From ab82917561bf654ca4a73a5f9ebe40b3e3d6bff3 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 22 Feb 2026 13:12:35 -0800 Subject: [PATCH 028/186] Add basic rendering Signed-off-by: Ryan Luu --- src/init.luau | 2173 +------------------------------------------------ 1 file changed, 15 insertions(+), 2158 deletions(-) diff --git a/src/init.luau b/src/init.luau index 6ed1e1b3..3980b8da 100644 --- a/src/init.luau +++ b/src/init.luau @@ -1,2167 +1,24 @@ ---!nolint DeprecatedApi +--!strict ---[[ - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. -]] - -local ContextActionService = game:GetService("ContextActionService") -local GuiService = game:GetService("GuiService") local Players = game:GetService("Players") -local RunService = game:GetService("RunService") -local StarterGui = game:GetService("StarterGui") -local TextChatService = game:GetService("TextChatService") -local UserInputService = game:GetService("UserInputService") -local VRService = game:GetService("VRService") -local PlayerGui: Instance = Players.LocalPlayer:WaitForChild("PlayerGui") - -local BackpackScript = {} - -BackpackScript.OpenClose = nil :: any -- Function to toggle open/close -BackpackScript.IsOpen = false :: boolean -BackpackScript.StateChanged = Instance.new("BindableEvent") :: BindableEvent -- Fires after any open/close, passes IsNowOpen - -BackpackScript.ModuleName = "Backpack" :: string -BackpackScript.KeepVRTopbarOpen = true :: boolean -BackpackScript.VRIsExclusive = true :: boolean -BackpackScript.VRClosesNonExclusive = true :: boolean - -BackpackScript.BackpackEmpty = Instance.new("BindableEvent") :: BindableEvent -- Fires when the backpack is empty (no tools -BackpackScript.BackpackEmpty.Name = "BackpackEmpty" - -BackpackScript.BackpackItemAdded = Instance.new("BindableEvent") :: BindableEvent -- Fires when an item is added to the backpack -BackpackScript.BackpackItemAdded.Name = "BackpackAdded" - -BackpackScript.BackpackItemRemoved = Instance.new("BindableEvent") :: BindableEvent -- Fires when an item is removed from the backpack -BackpackScript.BackpackItemRemoved.Name = "BackpackRemoved" - -local targetScript: ModuleScript = script - -require(script.Attribution) - --- Constants -- -local PREFERRED_TRANSPARENCY: number = GuiService.PreferredTransparency or 1 - --- Legacy behavior for backpack -local LEGACY_EDGE_ENABLED: boolean = not targetScript:GetAttribute("OutlineEquipBorder") or false -- Instead of the edge selection being inset, it will be on the outlined. LEGACY_PADDING must be enabled for this to work or this will do nothing -local LEGACY_PADDING_ENABLED: boolean = targetScript:GetAttribute("InsetIconPadding") -- Instead of the icon taking up the full slot, it will be padded on each side. - --- Background -local BACKGROUND_TRANSPARENCY_DEFAULT: number = targetScript:GetAttribute("BackgroundTransparency") or 0.3 -local BACKGROUND_TRANSPARENCY: number = BACKGROUND_TRANSPARENCY_DEFAULT * PREFERRED_TRANSPARENCY -local BACKGROUND_CORNER_RADIUS: UDim = UDim.new(0, 8) -local BACKGROUND_COLOR: Color3 = targetScript:GetAttribute("BackgroundColor3") - or Color3.new(25 / 255, 27 / 255, 29 / 255) - --- Slots -local SLOT_EQUIP_COLOR: Color3 = targetScript:GetAttribute("EquipBorderColor3") or Color3.new(0 / 255, 162 / 255, 1) -local SLOT_LOCKED_TRANSPARENCY_DEFAULT: number = targetScript:GetAttribute("BackgroundTransparency") or 0.3 -- Locked means undraggable -local SLOT_LOCKED_TRANSPARENCY: number = SLOT_LOCKED_TRANSPARENCY_DEFAULT * PREFERRED_TRANSPARENCY -local SLOT_EQUIP_THICKNESS: number = targetScript:GetAttribute("EquipBorderSizePixel") or 5 -- Relative -local SLOT_CORNER_RADIUS: UDim = targetScript:GetAttribute("CornerRadius") or UDim.new(0, 8) -local SLOT_BORDER_COLOR: Color3 = Color3.new(1, 1, 1) -- Appears when dragging - --- Tooltips -local TOOLTIP_CORNER_RADIUS: UDim = SLOT_CORNER_RADIUS - UDim.new(0, 5) or UDim.new(0, 3) -local TOOLTIP_BACKGROUND_COLOR: Color3 = targetScript:GetAttribute("BackgroundColor3") - or Color3.new(25 / 255, 27 / 255, 29 / 255) -local TOOLTIP_PADDING: number = 4 -local TOOLTIP_HEIGHT: number = 16 -local TOOLTIP_OFFSET: number = -5 -- From to - --- Topbar icons -local ARROW_IMAGE_OPEN: string = "rbxasset://textures/ui/TopBar/inventoryOn.png" -local ARROW_IMAGE_CLOSE: string = "rbxasset://textures/ui/TopBar/inventoryOff.png" --- local ARROW_HOTKEY: { Enum.KeyCode } = { Enum.KeyCode.Backquote, Enum.KeyCode.DPadUp } --TODO: Hookup '~' too? - --- Hotbar slots -local HOTBAR_SLOTS_FULL: number = 10 -- 10 is the max -local HOTBAR_SLOTS_VR: number = 6 -local HOTBAR_SLOTS_MINI: number = 6 -- Mobile gets 6 slots instead of default 3 it had before -local HOTBAR_SLOTS_WIDTH_CUTOFF: number = 1024 -- Anything smaller is MINI - -local INVENTORY_ROWS_FULL: number = 4 -local INVENTORY_ROWS_VR: number = 3 -local INVENTORY_ROWS_MINI: number = 2 -local INVENTORY_HEADER_SIZE: number = 40 -local INVENTORY_ARROWS_BUFFER_VR: number = 40 - --- Text -local TEXT_COLOR: Color3 = targetScript:GetAttribute("TextColor3") or Color3.new(1, 1, 1) -local TEXT_STROKE_TRANSPARENCY: number = targetScript:GetAttribute("TextStrokeTransparency") or 0.5 -local TEXT_STROKE_COLOR: Color3 = targetScript:GetAttribute("TextStrokeColor3") or Color3.new(0, 0, 0) - --- Search -local SEARCH_BACKGROUND_COLOR: Color3 = Color3.new(25 / 255, 27 / 255, 29 / 255) -local SEARCH_BACKGROUND_TRANSPARENCY_DEFAULT: number = 0.2 -local SEARCH_BACKGROUND_TRANSPARENCY: number = SEARCH_BACKGROUND_TRANSPARENCY_DEFAULT * PREFERRED_TRANSPARENCY -local SEARCH_BORDER_COLOR: Color3 = Color3.new(1, 1, 1) -local SEARCH_BORDER_TRANSPARENCY: number = 0.8 -local SEARCH_BORDER_THICKNESS: number = 1 -local SEARCH_TEXT_PLACEHOLDER: string = "Search" -local SEARCH_TEXT_OFFSET: number = 8 -local SEARCH_TEXT: string = "" -local SEARCH_CORNER_RADIUS: UDim = UDim.new(0, 3) -local SEARCH_IMAGE_X: string = "rbxasset://textures/ui/InspectMenu/x.png" -local SEARCH_BUFFER_PIXELS: number = 5 -local SEARCH_WIDTH_PIXELS: number = 200 - --- Misc -local FONT_FAMILY: Font = targetScript:GetAttribute("FontFace") - or Font.new("rbxasset://fonts/families/BuilderSans.json") -local FONT_SIZE: number = targetScript:GetAttribute("TextSize") or 16 -local DROP_HOTKEY_VALUE: number = Enum.KeyCode.Backspace.Value -local ZERO_KEY_VALUE: number = Enum.KeyCode.Zero.Value -local DOUBLE_CLICK_TIME: number = 0.5 -local ICON_BUFFER_PIXELS: number = 5 -local ICON_SIZE_PIXELS: number = 60 - -local MOUSE_INPUT_TYPES: { [Enum.UserInputType]: boolean } = - { -- These are the input types that will be used for mouse -- [[ADDED]], Optional - [Enum.UserInputType.MouseButton1] = true, - [Enum.UserInputType.MouseButton2] = true, - [Enum.UserInputType.MouseButton3] = true, - [Enum.UserInputType.MouseMovement] = true, - [Enum.UserInputType.MouseWheel] = true, - } - -local GAMEPAD_INPUT_TYPES: { [Enum.UserInputType]: boolean } = - { -- These are the input types that will be used for gamepad - [Enum.UserInputType.Gamepad1] = true, - [Enum.UserInputType.Gamepad2] = true, - [Enum.UserInputType.Gamepad3] = true, - [Enum.UserInputType.Gamepad4] = true, - [Enum.UserInputType.Gamepad5] = true, - [Enum.UserInputType.Gamepad6] = true, - [Enum.UserInputType.Gamepad7] = true, - [Enum.UserInputType.Gamepad8] = true, - } - --- Topbar logic -local BackpackEnabled: boolean = true - -local Icon: any = require(script.Parent.topbarplus) - -local inventoryIcon: any = Icon.new() - :setName("Inventory") - :setImage(ARROW_IMAGE_OPEN, "Selected") - :setImage(ARROW_IMAGE_CLOSE, "Deselected") - :setImageScale(1) - :setCaption("Inventory") - :bindToggleKey(Enum.KeyCode.Backquote) - :autoDeselect(false) - :setOrder(-1) - -inventoryIcon.toggled:Connect(function(): () - if not GuiService.MenuIsOpen then - BackpackScript.OpenClose() - end -end) - -local BackpackGui: ScreenGui = Instance.new("ScreenGui") -BackpackGui.DisplayOrder = 120 -BackpackGui.IgnoreGuiInset = true -BackpackGui.ResetOnSpawn = false -BackpackGui.Name = "BackpackGui" -BackpackGui.Parent = PlayerGui - -local IsTenFootInterface: boolean = GuiService:IsTenFootInterface() -if IsTenFootInterface then - ICON_SIZE_PIXELS = 100 - FONT_SIZE = 24 -end - -local GamepadActionsBound: boolean = false - -local IS_PHONE: boolean = UserInputService.TouchEnabled - and workspace.CurrentCamera.ViewportSize.X < HOTBAR_SLOTS_WIDTH_CUTOFF - -local Player: Player = Players.LocalPlayer - -local MainFrame: Frame = nil -local HotbarFrame: Frame = nil -local InventoryFrame: Frame = nil -local VRInventorySelector: any = nil -local ScrollingFrame: ScrollingFrame = nil -local UIGridFrame: Frame = nil -local UIGridLayout: UIGridLayout = nil -local ScrollUpInventoryButton: any = nil -local ScrollDownInventoryButton: any = nil -local changeToolFunc: any = nil - -local Character: Model = Player.Character or Player.CharacterAdded:Wait() -local Humanoid: any = Character:WaitForChild("Humanoid") -local Backpack: Instance = Player:WaitForChild("Backpack") - -local Slots = {} -- List of all Slots by index -local LowestEmptySlot: any = nil -local SlotsByTool = {} -- Map of Tools to their assigned Slots -local HotkeyFns = {} -- Map of KeyCode values to their assigned behaviors -local Dragging: { boolean } = {} -- Only used to check if anything is being dragged, to disable other input -local FullHotbarSlots: number = 0 -- Now being used to also determine whether or not LB and RB on the gamepad are enabled. -local ActiveHopper = nil -- NOTE: HopperBin -local StarterToolFound: boolean = false -- Special handling is required for the gear currently equipped on the site -local WholeThingEnabled: boolean = false -local TextBoxFocused: boolean = false -- ANY TextBox, not just the search box -local ViewingSearchResults: boolean = false -- If the results of a search are currently being viewed --- local HotkeyStrings = {} -- Used for eating/releasing hotkeys -local CharConns: { RBXScriptConnection } = {} -- Holds character Connections to be cleared later -local GamepadEnabled: boolean = false -- determines if our gui needs to be gamepad friendly - -local IsVR: boolean = VRService.VREnabled -- Are we currently using a VR device? -local NumberOfHotbarSlots: number = IsVR and HOTBAR_SLOTS_VR or (IS_PHONE and HOTBAR_SLOTS_MINI or HOTBAR_SLOTS_FULL) -- Number of slots shown at the bottom -local NumberOfInventoryRows: number = IsVR and INVENTORY_ROWS_VR - or (IS_PHONE and INVENTORY_ROWS_MINI or INVENTORY_ROWS_FULL) -- How many rows in the popped-up inventory -local BackpackPanel = nil -local lastEquippedSlot: any = nil - -local function EvaluateBackpackPanelVisibility(enabled: boolean): boolean - return enabled and inventoryIcon.enabled and BackpackEnabled and VRService.VREnabled -end - -local function ShowVRBackpackPopup(): () - if BackpackPanel and EvaluateBackpackPanelVisibility(true) then - BackpackPanel:ForceShowForSeconds(2) - end -end - -local function FindLowestEmpty(): number? - for i: number = 1, NumberOfHotbarSlots do - local slot: any = Slots[i] - if not slot.Tool then - return slot - end - end - return nil -end - -local function isInventoryEmpty(): boolean - for i: number = NumberOfHotbarSlots + 1, #Slots do - local slot: any = Slots[i] - if slot and slot.Tool then - return false - end - end - return true -end - -BackpackScript.IsInventoryEmpty = isInventoryEmpty - -local function UseGazeSelection(): boolean - return false -- disabled in new VR system -end - -local function AdjustHotbarFrames(): () - local inventoryOpen: boolean = InventoryFrame.Visible -- (Show all) - local visualTotal: number = inventoryOpen and NumberOfHotbarSlots or FullHotbarSlots - local visualIndex: number = 0 - - for i: number = 1, NumberOfHotbarSlots do - local slot: any = Slots[i] - if slot.Tool or inventoryOpen then - visualIndex = visualIndex + 1 - slot:Readjust(visualIndex, visualTotal) - slot.Frame.Visible = true - else - slot.Frame.Visible = false - end - end -end - -local function UpdateScrollingFrameCanvasSize(): () - local countX: number = math.floor(ScrollingFrame.AbsoluteSize.X / (ICON_SIZE_PIXELS + ICON_BUFFER_PIXELS)) - local maxRow: number = math.ceil((#UIGridFrame:GetChildren() - 1) / countX) - local canvasSizeY: number = maxRow * (ICON_SIZE_PIXELS + ICON_BUFFER_PIXELS) + ICON_BUFFER_PIXELS - ScrollingFrame.CanvasSize = UDim2.fromOffset(0, canvasSizeY) -end - -local function AdjustInventoryFrames(): () - for i: number = NumberOfHotbarSlots + 1, #Slots do - local slot: any = Slots[i] - slot.Frame.LayoutOrder = slot.Index - slot.Frame.Visible = (slot.Tool ~= nil) - end - UpdateScrollingFrameCanvasSize() -end - -local function UpdateBackpackLayout(): () - HotbarFrame.Size = UDim2.new( - 0, - ICON_BUFFER_PIXELS + (NumberOfHotbarSlots * (ICON_SIZE_PIXELS + ICON_BUFFER_PIXELS)), - 0, - ICON_BUFFER_PIXELS + ICON_SIZE_PIXELS + ICON_BUFFER_PIXELS - ) - HotbarFrame.Position = UDim2.new(0.5, -HotbarFrame.Size.X.Offset / 2, 1, -HotbarFrame.Size.Y.Offset) - InventoryFrame.Size = UDim2.new( - 0, - HotbarFrame.Size.X.Offset, - 0, - (HotbarFrame.Size.Y.Offset * NumberOfInventoryRows) - + INVENTORY_HEADER_SIZE - + (IsVR and 2 * INVENTORY_ARROWS_BUFFER_VR or 0) - ) - InventoryFrame.Position = UDim2.new( - 0.5, - -InventoryFrame.Size.X.Offset / 2, - 1, - HotbarFrame.Position.Y.Offset - InventoryFrame.Size.Y.Offset - ) - - ScrollingFrame.Size = UDim2.new( - 1, - ScrollingFrame.ScrollBarThickness + 1, - 1, - -INVENTORY_HEADER_SIZE - (IsVR and 2 * INVENTORY_ARROWS_BUFFER_VR or 0) - ) - ScrollingFrame.Position = UDim2.fromOffset(0, INVENTORY_HEADER_SIZE + (IsVR and INVENTORY_ARROWS_BUFFER_VR or 0)) - AdjustHotbarFrames() - AdjustInventoryFrames() -end - -local function Clamp(low: number, high: number, num: number): number - return math.min(high, math.max(low, num)) -end - -local function CheckBounds(guiObject: GuiObject, x: number, y: number): boolean - local pos: Vector2 = guiObject.AbsolutePosition - local size: Vector2 = guiObject.AbsoluteSize - return (x > pos.X and x <= pos.X + size.X and y > pos.Y and y <= pos.Y + size.Y) -end - -local function GetOffset(guiObject: GuiObject, point: Vector2): number - local centerPoint: Vector2 = guiObject.AbsolutePosition + (guiObject.AbsoluteSize / 2) - return (centerPoint - point).Magnitude -end - -local function DisableActiveHopper(): () --NOTE: HopperBin - ActiveHopper:ToggleSelect() - SlotsByTool[ActiveHopper]:UpdateEquipView() - ActiveHopper = nil :: any -end - -local function UnequipAllTools(): () --NOTE: HopperBin - if Humanoid then - Humanoid:UnequipTools() - if ActiveHopper then - DisableActiveHopper() - end - end -end - -local function EquipNewTool(tool: Tool): () --NOTE: HopperBin - UnequipAllTools() - Humanoid:EquipTool(tool) --NOTE: This would also unequip current Tool - --tool.Parent = Character --TODO: Switch back to above line after EquipTool is fixed! -end - -local function IsEquipped(tool: Tool): boolean - return tool and tool.Parent == Character --NOTE: HopperBin -end - --- Create a slot -local function MakeSlot(parent: Instance, initIndex: number?): GuiObject - local index: number = initIndex or (#Slots + 1) - - -- Slot Definition -- - - local slot: any = {} - slot.Tool = nil :: any - slot.Index = index :: number - slot.Frame = nil :: any - - local SlotFrame: any = nil - local FakeSlotFrame: Frame = nil - local ToolIcon: ImageLabel = nil - local ToolName: TextLabel = nil - local ToolChangeConn: any = nil - local HighlightFrame: any = nil -- UIStroke - local SelectionObj: ImageLabel = nil - - --NOTE: The following are only defined for Hotbar Slots - local ToolTip: TextLabel = nil - local SlotNumber: TextLabel = nil - - -- Slot Functions -- - - -- Update slot transparency - local function UpdateSlotFading(): () - SlotFrame.SelectionImageObject = nil - SlotFrame.BackgroundTransparency = SlotFrame.Draggable and 0 or SLOT_LOCKED_TRANSPARENCY - end - - -- Adjust the slots to the centered - function slot:Readjust(visualIndex: number, visualTotal: number): ...any --NOTE: Only used for Hotbar slots - local centered: number = HotbarFrame.Size.X.Offset / 2 - local sizePlus: number = ICON_BUFFER_PIXELS + ICON_SIZE_PIXELS - local midpointish: number = (visualTotal / 2) + 0.5 - local factor: number = visualIndex - midpointish - SlotFrame.Position = - UDim2.fromOffset(centered - (ICON_SIZE_PIXELS / 2) + (sizePlus * factor), ICON_BUFFER_PIXELS) - end - - -- Fill the slot with a tool - function slot:Fill(tool: Tool): ...any - -- Clear slot if it has no tool else assign the tool - if not tool then - return self:Clear() - end - - self.Tool = tool :: Tool - - -- Update the slot with tool data - local function assignToolData(): () - local icon: string = tool.TextureId - ToolIcon.Image = icon - - if icon ~= "" then - -- Enable the tool name on the slot if there is no icon - ToolName.Visible = false - else - ToolName.Visible = true - end - - ToolName.Text = tool.Name - - -- If there is a tooltip, then show it - if ToolTip and tool:IsA("Tool") then --NOTE: HopperBin - ToolTip.Text = tool.ToolTip - ToolTip.Size = UDim2.fromOffset(0, TOOLTIP_HEIGHT) - ToolTip.Position = UDim2.new(0.5, 0, 0, TOOLTIP_OFFSET) - end - end - assignToolData() - - -- Disconnect tool event if it exists - if ToolChangeConn then - ToolChangeConn:Disconnect() - ToolChangeConn = nil - end - - -- Update the slot with new tool data if the tool's properties changes - ToolChangeConn = tool.Changed:Connect(function(property: string): () - if property == "TextureId" or property == "Name" or property == "ToolTip" then - assignToolData() - end - end) - - local hotbarSlot: boolean = (self.Index <= NumberOfHotbarSlots) - local inventoryOpen: boolean = InventoryFrame.Visible - - if (not hotbarSlot or inventoryOpen) and not UserInputService.VREnabled then - SlotFrame.Draggable = true - end - - self:UpdateEquipView() - - if hotbarSlot then - FullHotbarSlots = FullHotbarSlots + 1 - -- If using a controller, determine whether or not we can enable BindCoreAction("BackpackHotbarEquip", etc) - if WholeThingEnabled and FullHotbarSlots >= 1 and not GamepadActionsBound then - -- Player added first item to a hotbar slot, enable BindCoreAction - GamepadActionsBound = true - ContextActionService:BindAction( - "BackpackHotbarEquip", - changeToolFunc, - false, - Enum.KeyCode.ButtonL1, - Enum.KeyCode.ButtonR1 - ) - end - end - - SlotsByTool[tool] = self - LowestEmptySlot = FindLowestEmpty() - end - - -- Empty the slot of any tool data - function slot:Clear(): ...any - if not self.Tool then - return - end - - -- Disconnect tool event if it exists - if ToolChangeConn then - ToolChangeConn:Disconnect() - ToolChangeConn = nil - end - - ToolIcon.Image = "" - ToolName.Text = "" - if ToolTip then - ToolTip.Text = "" - ToolTip.Visible = false - end - SlotFrame.Draggable = false - - self:UpdateEquipView(true) -- Show as unequipped - - if self.Index <= NumberOfHotbarSlots then - FullHotbarSlots = FullHotbarSlots - 1 - if FullHotbarSlots < 1 then - -- Player removed last item from hotbar; UnbindCoreAction("BackpackHotbarEquip"), allowing the developer to use LB and RB. - GamepadActionsBound = false - ContextActionService:UnbindAction("BackpackHotbarEquip") - end - end - - SlotsByTool[self.Tool] = nil - self.Tool = nil - LowestEmptySlot = FindLowestEmpty() - end - - function slot:UpdateEquipView(unequippedOverride: boolean?): ...any - local override = unequippedOverride or false - if not override and IsEquipped(self.Tool) then -- Equipped - lastEquippedSlot = slot - if not HighlightFrame then - HighlightFrame = Instance.new("UIStroke") - HighlightFrame.Name = "Border" - HighlightFrame.Thickness = SLOT_EQUIP_THICKNESS - HighlightFrame.Color = SLOT_EQUIP_COLOR - HighlightFrame.ApplyStrokeMode = Enum.ApplyStrokeMode.Border - end - if LEGACY_EDGE_ENABLED == true then - HighlightFrame.Parent = ToolIcon - else - HighlightFrame.Parent = SlotFrame - end - else -- In the Backpack - if HighlightFrame then - HighlightFrame.Parent = nil - end - end - UpdateSlotFading() - end - - function slot:IsEquipped(): boolean - return IsEquipped(self.Tool) - end - - function slot:Delete(): ...any - SlotFrame:Destroy() --NOTE: Also clears connections - table.remove(Slots, self.Index) - local newSize: number = #Slots - - -- Now adjust the rest (both visually and representationally) - for slotIndex: number = self.Index :: number, newSize :: number do - Slots[slotIndex]:SlideBack() - end - - UpdateScrollingFrameCanvasSize() - end - - function slot:Swap(targetSlot: any): ...any --NOTE: This slot (self) must not be empty! - local myTool: any, otherTool: any = self.Tool, targetSlot.Tool - self:Clear() - if otherTool then -- (Target slot might be empty) - targetSlot:Clear() - self:Fill(otherTool) - end - if myTool then - targetSlot:Fill(myTool) - else - targetSlot:Clear() - end - end - - function slot:SlideBack(): ...any -- For inventory slot shifting - self.Index = self.Index - 1 - SlotFrame.Name = self.Index - SlotFrame.LayoutOrder = self.Index - end - - function slot:TurnNumber(on: boolean): ...any - if SlotNumber then - SlotNumber.Visible = on - end - end - - function slot:SetClickability(on: boolean): ...any -- (Happens on open/close arrow) - if self.Tool then - if UserInputService.VREnabled then - SlotFrame.Draggable = false - else - SlotFrame.Draggable = not on - end - UpdateSlotFading() - end - end - - function slot:CheckTerms(terms: any): number - local hits: number = 0 - local function checkEm(str: string, term: any): () - local _, n: number = str:lower():gsub(term, "") - hits = hits + n - end - local tool: Tool = self.Tool - if tool then - for term: any in pairs(terms) do - checkEm(ToolName.Text, term) - if tool:IsA("Tool") then --NOTE: HopperBin - local toolTipText: string = ToolTip and ToolTip.Text or "" - checkEm(toolTipText, term) - end - end - end - return hits - end - - -- Slot select logic, activated by clicking or pressing hotkey - function slot:Select(): ...any - local tool: Tool = slot.Tool - if tool then - if IsEquipped(tool) then --NOTE: HopperBin - UnequipAllTools() - elseif tool.Parent == Backpack then - EquipNewTool(tool) - end - end - end - - -- Slot Init Logic -- - - SlotFrame = Instance.new("TextButton") - SlotFrame.Name = tostring(index) - SlotFrame.BackgroundColor3 = BACKGROUND_COLOR - SlotFrame.BorderColor3 = SLOT_BORDER_COLOR - SlotFrame.Text = "" - SlotFrame.BorderSizePixel = 0 - SlotFrame.Size = UDim2.fromOffset(ICON_SIZE_PIXELS, ICON_SIZE_PIXELS) - SlotFrame.Active = true - SlotFrame.Draggable = false - SlotFrame.BackgroundTransparency = SLOT_LOCKED_TRANSPARENCY - SlotFrame.MouseButton1Click:Connect(function(): () - changeSlot(slot) - end) - local searchFrameCorner: UICorner = Instance.new("UICorner") - searchFrameCorner.Name = "Corner" - searchFrameCorner.CornerRadius = SLOT_CORNER_RADIUS - searchFrameCorner.Parent = SlotFrame - slot.Frame = SlotFrame - - do - local selectionObjectClipper: Frame = Instance.new("Frame") - selectionObjectClipper.Name = "SelectionObjectClipper" - selectionObjectClipper.BackgroundTransparency = 1 - selectionObjectClipper.Visible = false - selectionObjectClipper.Parent = SlotFrame - - SelectionObj = Instance.new("ImageLabel") - SelectionObj.Name = "Selector" - SelectionObj.BackgroundTransparency = 1 - SelectionObj.Size = UDim2.fromScale(1, 1) - SelectionObj.Image = "rbxasset://textures/ui/Keyboard/key_selection_9slice.png" - SelectionObj.ScaleType = Enum.ScaleType.Slice - SelectionObj.SliceCenter = Rect.new(12, 12, 52, 52) - SelectionObj.Parent = selectionObjectClipper - end - - ToolIcon = Instance.new("ImageLabel") - ToolIcon.BackgroundTransparency = 1 - ToolIcon.Name = "Icon" - ToolIcon.Size = UDim2.fromScale(1, 1) - ToolIcon.Position = UDim2.fromScale(0.5, 0.5) - ToolIcon.AnchorPoint = Vector2.new(0.5, 0.5) - if LEGACY_PADDING_ENABLED == true then - ToolIcon.Size = UDim2.new(1, -SLOT_EQUIP_THICKNESS * 2, 1, -SLOT_EQUIP_THICKNESS * 2) - else - ToolIcon.Size = UDim2.fromScale(1, 1) - end - ToolIcon.Parent = SlotFrame - - local ToolIconCorner: UICorner = Instance.new("UICorner") - ToolIconCorner.Name = "Corner" - if LEGACY_PADDING_ENABLED == true then - ToolIconCorner.CornerRadius = SLOT_CORNER_RADIUS - UDim.new(0, SLOT_EQUIP_THICKNESS) - else - ToolIconCorner.CornerRadius = SLOT_CORNER_RADIUS - end - ToolIconCorner.Parent = ToolIcon - - ToolName = Instance.new("TextLabel") - ToolName.BackgroundTransparency = 1 - ToolName.Name = "ToolName" - ToolName.Text = "" - ToolName.TextColor3 = TEXT_COLOR - ToolName.TextStrokeTransparency = TEXT_STROKE_TRANSPARENCY - ToolName.TextStrokeColor3 = TEXT_STROKE_COLOR - ToolName.FontFace = Font.new(FONT_FAMILY.Family, Enum.FontWeight.Medium, Enum.FontStyle.Normal) - ToolName.TextSize = FONT_SIZE - ToolName.Size = UDim2.new(1, -SLOT_EQUIP_THICKNESS * 2, 1, -SLOT_EQUIP_THICKNESS * 2) - ToolName.Position = UDim2.fromScale(0.5, 0.5) - ToolName.AnchorPoint = Vector2.new(0.5, 0.5) - ToolName.TextWrapped = true - ToolName.TextTruncate = Enum.TextTruncate.AtEnd - ToolName.Parent = SlotFrame - - slot.Frame.LayoutOrder = slot.Index - - if index <= NumberOfHotbarSlots then -- Hotbar-Specific Slot Stuff - -- ToolTip stuff - ToolTip = Instance.new("TextLabel") - ToolTip.Name = "ToolTip" - ToolTip.Text = "" - ToolTip.Size = UDim2.fromScale(1, 1) - ToolTip.TextColor3 = TEXT_COLOR - ToolTip.TextStrokeTransparency = TEXT_STROKE_TRANSPARENCY - ToolTip.TextStrokeColor3 = TEXT_STROKE_COLOR - ToolTip.FontFace = Font.new(FONT_FAMILY.Family, Enum.FontWeight.Medium, Enum.FontStyle.Normal) - ToolTip.TextSize = FONT_SIZE - ToolTip.ZIndex = 2 - ToolTip.TextWrapped = false - ToolTip.TextYAlignment = Enum.TextYAlignment.Center - ToolTip.BackgroundColor3 = TOOLTIP_BACKGROUND_COLOR - ToolTip.BackgroundTransparency = SLOT_LOCKED_TRANSPARENCY - ToolTip.AnchorPoint = Vector2.new(0.5, 1) - ToolTip.BorderSizePixel = 0 - ToolTip.Visible = false - ToolTip.AutomaticSize = Enum.AutomaticSize.X - ToolTip.Parent = SlotFrame - - local ToolTipCorner: UICorner = Instance.new("UICorner") - ToolTipCorner.Name = "Corner" - ToolTipCorner.CornerRadius = TOOLTIP_CORNER_RADIUS - ToolTipCorner.Parent = ToolTip - - local ToolTipPadding: UIPadding = Instance.new("UIPadding") - ToolTipPadding.PaddingLeft = UDim.new(0, TOOLTIP_PADDING) - ToolTipPadding.PaddingRight = UDim.new(0, TOOLTIP_PADDING) - ToolTipPadding.PaddingTop = UDim.new(0, TOOLTIP_PADDING) - ToolTipPadding.PaddingBottom = UDim.new(0, TOOLTIP_PADDING) - ToolTipPadding.Parent = ToolTip - SlotFrame.MouseEnter:Connect(function(): () - if ToolTip.Text ~= "" then - ToolTip.Visible = true - end - end) - SlotFrame.MouseLeave:Connect(function(): () - ToolTip.Visible = false - end) - - function slot:MoveToInventory(): ...any - if slot.Index <= NumberOfHotbarSlots then -- From a Hotbar slot - local tool: any = slot.Tool - self:Clear() --NOTE: Order matters here - local newSlot: any = MakeSlot(UIGridFrame) - newSlot:Fill(tool) - if IsEquipped(tool) then -- Also unequip it --NOTE: HopperBin - UnequipAllTools() - end - -- Also hide the inventory slot if we're showing results right now - if ViewingSearchResults then - newSlot.Frame.Visible = false - newSlot.Parent = InventoryFrame - end - end - end - - -- Show label and assign hotkeys for 1-9 and 0 (zero is always last slot when > 10 total) - if index < 10 or index == NumberOfHotbarSlots then -- NOTE: Hardcoded on purpose! - local slotNum: number = (index < 10) and index or 0 - SlotNumber = Instance.new("TextLabel") - SlotNumber.BackgroundTransparency = 1 - SlotNumber.Name = "Number" - SlotNumber.TextColor3 = TEXT_COLOR - SlotNumber.TextStrokeTransparency = TEXT_STROKE_TRANSPARENCY - SlotNumber.TextStrokeColor3 = TEXT_STROKE_COLOR - SlotNumber.TextSize = FONT_SIZE - SlotNumber.Text = tostring(slotNum) - SlotNumber.FontFace = Font.new(FONT_FAMILY.Family, Enum.FontWeight.Heavy, Enum.FontStyle.Normal) - SlotNumber.Size = UDim2.fromScale(0.4, 0.4) - SlotNumber.Visible = false - SlotNumber.Parent = SlotFrame - HotkeyFns[ZERO_KEY_VALUE + slotNum] = slot.Select - end - end - - do -- Dragging Logic - local startPoint: UDim2 = SlotFrame.Position - local lastUpTime: number = 0 - local startParent: any = nil - - SlotFrame.DragBegin:Connect(function(dragPoint: UDim2): () - Dragging[SlotFrame] = true - startPoint = dragPoint - - SlotFrame.BorderSizePixel = 2 - inventoryIcon:lock() - - -- Raise above other slots - SlotFrame.ZIndex = 2 - ToolIcon.ZIndex = 2 - ToolName.ZIndex = 2 - SlotFrame.Parent.ZIndex = 2 - if SlotNumber then - SlotNumber.ZIndex = 2 - end - -- if HighlightFrame then - -- HighlightFrame.ZIndex = 2 - -- for _, child in pairs(HighlightFrame:GetChildren()) do - -- child.ZIndex = 2 - -- end - -- end - - -- Circumvent the ScrollingFrame's ClipsDescendants property - startParent = SlotFrame.Parent - if startParent == UIGridFrame then - local newPosition: UDim2 = UDim2.new( - 0, - SlotFrame.AbsolutePosition.X - InventoryFrame.AbsolutePosition.X, - 0, - SlotFrame.AbsolutePosition.Y - InventoryFrame.AbsolutePosition.Y - ) - SlotFrame.Parent = InventoryFrame - SlotFrame.Position = newPosition - - FakeSlotFrame = Instance.new("Frame") - FakeSlotFrame.Name = "FakeSlot" - FakeSlotFrame.LayoutOrder = SlotFrame.LayoutOrder - FakeSlotFrame.Size = SlotFrame.Size - FakeSlotFrame.BackgroundTransparency = 1 - FakeSlotFrame.Parent = UIGridFrame - end - end) - - SlotFrame.DragStopped:Connect(function(x: number, y: number): () - if FakeSlotFrame then - FakeSlotFrame:Destroy() - end - - local now: number = os.clock() - - SlotFrame.Position = startPoint - SlotFrame.Parent = startParent - - SlotFrame.BorderSizePixel = 0 - inventoryIcon:unlock() - - -- Restore height - SlotFrame.ZIndex = 1 - ToolIcon.ZIndex = 1 - ToolName.ZIndex = 1 - startParent.ZIndex = 1 - - if SlotNumber then - SlotNumber.ZIndex = 1 - end - -- if HighlightFrame then - -- HighlightFrame.ZIndex = 1 - -- for _, child in pairs(HighlightFrame:GetChildren()) do - -- child.ZIndex = 1 - -- end - -- end - - Dragging[SlotFrame] = nil - - -- Make sure the tool wasn't dropped - if not slot.Tool then - return - end - - -- Check where we were dropped - if CheckBounds(InventoryFrame, x, y) then - if slot.Index <= NumberOfHotbarSlots then - slot:MoveToInventory() - end - -- Check for double clicking on an inventory slot, to move into empty hotbar slot - if slot.Index > NumberOfHotbarSlots and now - lastUpTime < DOUBLE_CLICK_TIME then - if LowestEmptySlot then - local myTool: any = slot.Tool - slot:Clear() - LowestEmptySlot:Fill(myTool) - slot:Delete() - end - now = 0 -- Resets the timer - end - elseif CheckBounds(HotbarFrame, x, y) then - local closest: { number } = { math.huge, nil :: any } - for i: number = 1, NumberOfHotbarSlots do - local otherSlot: any = Slots[i] - local offset: number = GetOffset(otherSlot.Frame, Vector2.new(x, y)) - if offset < closest[1] then - closest = { offset, otherSlot } - end - end - local closestSlot: any = closest[2] - if closestSlot ~= slot then - slot:Swap(closestSlot) - if slot.Index > NumberOfHotbarSlots then - local tool: Tool = slot.Tool - if not tool then -- Clean up after ourselves if we're an inventory slot that's now empty - slot:Delete() - else -- Moved inventory slot to hotbar slot, and gained a tool that needs to be unequipped - if IsEquipped(tool) then --NOTE: HopperBin - UnequipAllTools() - end - -- Also hide the inventory slot if we're showing results right now - if ViewingSearchResults then - slot.Frame.Visible = false - slot.Frame.Parent = InventoryFrame - end - end - end - end - else - -- local tool = slot.Tool - -- if tool.CanBeDropped then --TODO: HopperBins - -- tool.Parent = workspace - -- --TODO: Move away from character - -- end - if slot.Index <= NumberOfHotbarSlots then - slot:MoveToInventory() --NOTE: Temporary - end - end - - lastUpTime = now - end) - end - - -- All ready! - SlotFrame.Parent = parent - Slots[index] = slot - - if index > NumberOfHotbarSlots then - UpdateScrollingFrameCanvasSize() - -- Scroll to new inventory slot, if we're open and not viewing search results - if InventoryFrame.Visible and not ViewingSearchResults then - local offset: number = ScrollingFrame.CanvasSize.Y.Offset - ScrollingFrame.AbsoluteSize.Y - ScrollingFrame.CanvasPosition = Vector2.new(0, math.max(0, offset)) - end - end - - return slot -end - -local function OnChildAdded(child: Instance): () -- To Character or Backpack - if not child:IsA("Tool") and not child:IsA("HopperBin") then --NOTE: HopperBin - if child:IsA("Humanoid") and child.Parent == Character then - Humanoid = child - end - return - end - local tool: any = child - - if tool.Parent == Character then - ShowVRBackpackPopup() - end - - if ActiveHopper and tool.Parent == Character then --NOTE: HopperBin - DisableActiveHopper() - end - - --TODO: Optimize / refactor / do something else - if not StarterToolFound and tool.Parent == Character and not SlotsByTool[tool] then - local starterGear: Instance? = Player:FindFirstChild("StarterGear") - if starterGear then - if starterGear:FindFirstChild(tool.Name) then - StarterToolFound = true - local slot: any = LowestEmptySlot or MakeSlot(UIGridFrame) - for i: number = slot.Index, 1, -1 do - local curr = Slots[i] -- An empty slot, because above - local pIndex: number = i - 1 - if pIndex > 0 then - local prev = Slots[pIndex] -- Guaranteed to be full, because above - prev:Swap(curr) - else - curr:Fill(tool) - end - end - -- Have to manually unequip a possibly equipped tool - for _, children: Instance in pairs(Character:GetChildren()) do - if children:IsA("Tool") and children ~= tool then - children.Parent = Backpack - end - end - AdjustHotbarFrames() - return -- We're done here - end - end - end - - -- The tool is either moving or new - local slot: any = SlotsByTool[tool] - if slot then - slot:UpdateEquipView() - else -- New! Put into lowest hotbar slot or new inventory slot - slot = LowestEmptySlot or MakeSlot(UIGridFrame) - slot:Fill(tool) - if slot.Index <= NumberOfHotbarSlots and not InventoryFrame.Visible then - AdjustHotbarFrames() - end - if tool:IsA("HopperBin") then --NOTE: HopperBin - if tool.Active then - UnequipAllTools() - ActiveHopper = tool - end - end - end - - BackpackScript.BackpackItemAdded:Fire(slot) -end - -local function OnChildRemoved(child: Instance): () -- From Character or Backpack - if not child:IsA("Tool") and not child:IsA("HopperBin") then --NOTE: HopperBin - return - end - local tool: Tool | any = child - - ShowVRBackpackPopup() - - -- Ignore this event if we're just moving between the two - local newParent: any = tool.Parent - if newParent == Character or newParent == Backpack then - return - end - - local slot: any = SlotsByTool[tool] - if slot then - slot:Clear() - if slot.Index > NumberOfHotbarSlots then -- Inventory slot - slot:Delete() - elseif not InventoryFrame.Visible then - AdjustHotbarFrames() - end - end - - if tool :: any == ActiveHopper then --NOTE: HopperBin - ActiveHopper = nil :: any - end - - if slot then - BackpackScript.BackpackItemRemoved:Fire(slot) - end - if isInventoryEmpty() then - BackpackScript.BackpackEmpty:Fire() - end -end - -local function OnCharacterAdded(character: Model): () - -- First, clean up any old slots - for i: number = #Slots, 1, -1 do - local slot = Slots[i] - if slot.Tool then - slot:Clear() - end - if i > NumberOfHotbarSlots then - slot:Delete() - end - end - ActiveHopper = nil :: any --NOTE: HopperBin - - -- And any old Connections - for _, conn: RBXScriptConnection in pairs(CharConns) do - conn:Disconnect() - end - CharConns = {} - - -- Hook up the new character - Character = character - table.insert(CharConns, character.ChildRemoved:Connect(OnChildRemoved)) - table.insert(CharConns, character.ChildAdded:Connect(OnChildAdded)) - for _, child: Instance in pairs(character:GetChildren()) do - OnChildAdded(child) - end - --NOTE: Humanoid is set inside OnChildAdded - - -- And the new backpack, when it gets here - Backpack = Player:WaitForChild("Backpack") - table.insert(CharConns, Backpack.ChildRemoved:Connect(OnChildRemoved)) - table.insert(CharConns, Backpack.ChildAdded:Connect(OnChildAdded)) - for _, child: Instance in pairs(Backpack:GetChildren()) do - OnChildAdded(child) - end - - AdjustHotbarFrames() -end - -local function OnInputBegan(input: InputObject, isProcessed: boolean): () - local ChatInputBarConfiguration = - TextChatService:FindFirstChildOfClass("ChatInputBarConfiguration") :: ChatInputBarConfiguration - -- Pass through keyboard hotkeys when not typing into a TextBox and not disabled (except for the Drop key) - if - input.UserInputType == Enum.UserInputType.Keyboard - and not TextBoxFocused - and not ChatInputBarConfiguration.IsFocused - and (WholeThingEnabled or input.KeyCode.Value == DROP_HOTKEY_VALUE) - then - local hotkeyBehavior: any = HotkeyFns[input.KeyCode.Value] - if hotkeyBehavior then - hotkeyBehavior(isProcessed) - end - end - - local inputType: Enum.UserInputType = input.UserInputType - if not isProcessed then - if inputType == Enum.UserInputType.MouseButton1 or inputType == Enum.UserInputType.Touch then - if InventoryFrame.Visible then - inventoryIcon:deselect() - end - end - end -end - -local function OnUISChanged(): () - -- Detect if player is using Touch - if UserInputService:GetLastInputType() == Enum.UserInputType.Touch then - for i: number = 1, NumberOfHotbarSlots do - Slots[i]:TurnNumber(false) - end - return - end - - -- Detect if player is using Keyboard - if UserInputService:GetLastInputType() == Enum.UserInputType.Keyboard then - for i: number = 1, NumberOfHotbarSlots do - Slots[i]:TurnNumber(true) - end - return - end - - -- Detect if player is using Mouse - for _, mouse: any in pairs(MOUSE_INPUT_TYPES) do - if UserInputService:GetLastInputType() == mouse then - for i: number = 1, NumberOfHotbarSlots do - Slots[i]:TurnNumber(true) - end - return - end - end - - -- Detect if player is using Controller - for _, gamepad: any in pairs(GAMEPAD_INPUT_TYPES) do - if UserInputService:GetLastInputType() == gamepad then - for i: number = 1, NumberOfHotbarSlots do - Slots[i]:TurnNumber(false) - end - return - end - end -end - -local lastChangeToolInputObject: InputObject = nil -local lastChangeToolInputTime: number = nil -local maxEquipDeltaTime: number = 0.06 -local noOpFunc = function() end --- local selectDirection = Vector2.new(0, 0) - -function unbindAllGamepadEquipActions(): () - ContextActionService:UnbindAction("BackpackHasGamepadFocus") - ContextActionService:UnbindAction("BackpackCloseInventory") -end - --- local function setHotbarVisibility(visible: boolean, isInventoryScreen: boolean) --- for i: number = 1, NumberOfHotbarSlots do --- local hotbarSlot = Slots[i] --- if hotbarSlot and hotbarSlot.Frame and (isInventoryScreen or hotbarSlot.Tool) then --- hotbarSlot.Frame.Visible = visible --- end --- end --- end - --- local function getInputDirection(inputObject: InputObject): Vector2 --- local buttonModifier = 1 --- if inputObject.UserInputState == Enum.UserInputState.End then --- buttonModifier = -1 --- end - --- if inputObject.KeyCode == Enum.KeyCode.Thumbstick1 then --- local Magnitude = inputObject.Position.Magnitude - --- if Magnitude > 0.98 then --- local normalizedVector = --- Vector2.new(inputObject.Position.X / Magnitude, -inputObject.Position.Y / Magnitude) --- selectDirection = normalizedVector --- else --- selectDirection = Vector2.new(0, 0) --- end --- elseif inputObject.KeyCode == Enum.KeyCode.DPadLeft then --- selectDirection = Vector2.new(selectDirection.X - 1 * buttonModifier, selectDirection.Y) --- elseif inputObject.KeyCode == Enum.KeyCode.DPadRight then --- selectDirection = Vector2.new(selectDirection.X + 1 * buttonModifier, selectDirection.Y) --- elseif inputObject.KeyCode == Enum.KeyCode.DPadUp then --- selectDirection = Vector2.new(selectDirection.X, selectDirection.Y - 1 * buttonModifier) --- elseif inputObject.KeyCode == Enum.KeyCode.DPadDown then --- selectDirection = Vector2.new(selectDirection.X, selectDirection.Y + 1 * buttonModifier) --- else --- selectDirection = Vector2.new(0, 0) --- end - --- return selectDirection --- end - --- local selectToolExperiment = function(actionName: string, inputState: Enum.UserInputState, inputObject: InputObject) --- local inputDirection = getInputDirection(inputObject) - --- if inputDirection == Vector2.new(0, 0) then --- return --- end - --- local angle = math.atan2(inputDirection.Y, inputDirection.X) - math.atan2(-1, 0) --- if angle < 0 then --- angle = angle + (math.pi * 2) --- end - --- local quarterPi = (math.pi * 0.25) - --- local index = (angle / quarterPi) + 1 --- index = math.floor(index + 0.5) -- round index to whole number --- if index > NumberOfHotbarSlots then --- index = 1 --- end - --- if index > 0 then --- local selectedSlot = Slots[index] --- if selectedSlot and selectedSlot.Tool and not selectedSlot:IsEquipped() then --- selectedSlot:Select() --- end --- else --- UnequipAllTools() --- end --- end - --- selene: allow(unused_variable) -changeToolFunc = function(actionName: string, inputState: Enum.UserInputState, inputObject: InputObject): () - if inputState ~= Enum.UserInputState.Begin then - return - end - - if lastChangeToolInputObject then - if - ( - lastChangeToolInputObject.KeyCode == Enum.KeyCode.ButtonR1 - and inputObject.KeyCode == Enum.KeyCode.ButtonL1 - ) - or ( - lastChangeToolInputObject.KeyCode == Enum.KeyCode.ButtonL1 - and inputObject.KeyCode == Enum.KeyCode.ButtonR1 - ) - then - if (os.clock() - lastChangeToolInputTime) <= maxEquipDeltaTime then - UnequipAllTools() - lastChangeToolInputObject = inputObject - lastChangeToolInputTime = os.clock() - return - end - end - end - - lastChangeToolInputObject = inputObject - lastChangeToolInputTime = os.clock() - - task.delay(maxEquipDeltaTime, function(): () - if lastChangeToolInputObject ~= inputObject then - return - end - - local moveDirection: number = 0 - if inputObject.KeyCode == Enum.KeyCode.ButtonL1 then - moveDirection = -1 - else - moveDirection = 1 - end - - for i: number = 1, NumberOfHotbarSlots do - local hotbarSlot: any = Slots[i] - if hotbarSlot:IsEquipped() then - local newSlotPosition: number = moveDirection + i - local hitEdge: boolean = false - if newSlotPosition > NumberOfHotbarSlots then - newSlotPosition = 1 - hitEdge = true - elseif newSlotPosition < 1 then - newSlotPosition = NumberOfHotbarSlots - hitEdge = true - end - - local origNewSlotPos: number = newSlotPosition - while not Slots[newSlotPosition].Tool do - newSlotPosition = newSlotPosition + moveDirection - if newSlotPosition == origNewSlotPos then - return - end - - if newSlotPosition > NumberOfHotbarSlots then - newSlotPosition = 1 - hitEdge = true - elseif newSlotPosition < 1 then - newSlotPosition = NumberOfHotbarSlots - hitEdge = true - end - end - - if hitEdge then - UnequipAllTools() - lastEquippedSlot = nil - else - Slots[newSlotPosition]:Select() - end - return - end - end - - if lastEquippedSlot and lastEquippedSlot.Tool then - lastEquippedSlot:Select() - return - end - - local startIndex: number = moveDirection == -1 and NumberOfHotbarSlots or 1 - local endIndex: number = moveDirection == -1 and 1 or NumberOfHotbarSlots - for i: number = startIndex, endIndex, moveDirection do - if Slots[i].Tool then - Slots[i]:Select() - return - end - end - end) -end - -function getGamepadSwapSlot(): any - for i: number = 1, #Slots do - if Slots[i].Frame.BorderSizePixel > 0 then - return Slots[i] - end - end - return -end - --- selene: allow(unused_variable) -function changeSlot(slot: any): () - local swapInVr: boolean = not VRService.VREnabled or InventoryFrame.Visible - - if slot.Frame == GuiService.SelectedObject and swapInVr then - local currentlySelectedSlot: any = getGamepadSwapSlot() - - if currentlySelectedSlot then - currentlySelectedSlot.Frame.BorderSizePixel = 0 - if currentlySelectedSlot ~= slot then - slot:Swap(currentlySelectedSlot) - VRInventorySelector.SelectionImageObject.Visible = false - - if slot.Index > NumberOfHotbarSlots and not slot.Tool then - if GuiService.SelectedObject == slot.Frame then - GuiService.SelectedObject = currentlySelectedSlot.Frame - end - slot:Delete() - end - - if currentlySelectedSlot.Index > NumberOfHotbarSlots and not currentlySelectedSlot.Tool then - if GuiService.SelectedObject == currentlySelectedSlot.Frame then - GuiService.SelectedObject = slot.Frame - end - currentlySelectedSlot:Delete() - end - end - else - local startSize: UDim2 = slot.Frame.Size - local startPosition: UDim2 = slot.Frame.Position - slot.Frame:TweenSizeAndPosition( - startSize + UDim2.fromOffset(10, 10), - startPosition - UDim2.fromOffset(5, 5), - Enum.EasingDirection.Out, - Enum.EasingStyle.Quad, - 0.1, - true, - function(): () - slot.Frame:TweenSizeAndPosition( - startSize, - startPosition, - Enum.EasingDirection.In, - Enum.EasingStyle.Quad, - 0.1, - true - ) - end - ) - slot.Frame.BorderSizePixel = 3 - VRInventorySelector.SelectionImageObject.Visible = true - end - else - slot:Select() - VRInventorySelector.SelectionImageObject.Visible = false - end -end - -function vrMoveSlotToInventory(): () - if not VRService.VREnabled then - return - end - - local currentlySelectedSlot: any = getGamepadSwapSlot() - if currentlySelectedSlot and currentlySelectedSlot.Tool then - currentlySelectedSlot.Frame.BorderSizePixel = 0 - currentlySelectedSlot:MoveToInventory() - VRInventorySelector.SelectionImageObject.Visible = false - end -end - -function enableGamepadInventoryControl(): () - local goBackOneLevel = function(): () - -- if inputState ~= Enum.UserInputState.Begin then - -- return - -- end - - local selectedSlot: any = getGamepadSwapSlot() - if selectedSlot then - -- selene: allow(shadowing) - local selectedSlot: any = getGamepadSwapSlot() - if selectedSlot then - selectedSlot.Frame.BorderSizePixel = 0 - return - end - elseif InventoryFrame.Visible then - inventoryIcon:deselect() - end - end - - ContextActionService:BindAction("BackpackHasGamepadFocus", noOpFunc, false, Enum.UserInputType.Gamepad1) - ContextActionService:BindAction( - "BackpackCloseInventory", - goBackOneLevel, - false, - Enum.KeyCode.ButtonB, - Enum.KeyCode.ButtonStart - ) - - -- Gaze select will automatically select the object for us! - if not UseGazeSelection() then - GuiService.SelectedObject = HotbarFrame:FindFirstChild("1") - end -end - -function disableGamepadInventoryControl(): () - unbindAllGamepadEquipActions() - - for i: number = 1, NumberOfHotbarSlots do - local hotbarSlot: any = Slots[i] - if hotbarSlot and hotbarSlot.Frame then - hotbarSlot.Frame.BorderSizePixel = 0 - end - end - - if GuiService.SelectedObject and GuiService.SelectedObject:IsDescendantOf(MainFrame) then - GuiService.SelectedObject = nil - end -end - -local function bindBackpackHotbarAction(): () - if WholeThingEnabled and not GamepadActionsBound then - GamepadActionsBound = true - ContextActionService:BindAction( - "BackpackHotbarEquip", - changeToolFunc, - false, - Enum.KeyCode.ButtonL1, - Enum.KeyCode.ButtonR1 - ) - end -end - -local function unbindBackpackHotbarAction(): () - disableGamepadInventoryControl() - GamepadActionsBound = false - ContextActionService:UnbindAction("BackpackHotbarEquip") -end - -function gamepadDisconnected(): () - GamepadEnabled = false - disableGamepadInventoryControl() -end - -function gamepadConnected(): () - GamepadEnabled = true - GuiService:AddSelectionParent("BackpackSelection", MainFrame) - - if FullHotbarSlots >= 1 then - bindBackpackHotbarAction() - end - - if InventoryFrame.Visible then - enableGamepadInventoryControl() - end -end - -local function OnIconChanged(enabled: boolean): () - -- Check for enabling/disabling the whole thing - local success, _topbarEnabled = pcall(function() - return enabled and StarterGui:GetCore("TopbarEnabled") - end) - - if not success then - return - end - - WholeThingEnabled = enabled - MainFrame.Visible = enabled - - -- Eat/Release hotkeys (Doesn't affect UserInputService) - -- for _, keyString in pairs(HotkeyStrings) do - -- if enabled then - -- GuiService:AddKey(keyString) - -- else - -- GuiService:RemoveKey(keyString) - -- end - -- end - - if enabled then - if FullHotbarSlots >= 1 then - bindBackpackHotbarAction() - end - else - unbindBackpackHotbarAction() - end -end - -local function MakeVRRoundButton(name: string, image: string): (ImageButton, ImageLabel, ImageLabel) - local newButton: ImageButton = Instance.new("ImageButton") - newButton.BackgroundTransparency = 1 - newButton.Name = name - newButton.Size = UDim2.fromOffset(40, 40) - newButton.Image = "rbxasset://textures/ui/Keyboard/close_button_background.png" - - local buttonIcon: ImageLabel = Instance.new("ImageLabel") - buttonIcon.Name = "Icon" - buttonIcon.BackgroundTransparency = 1 - buttonIcon.Size = UDim2.fromScale(0.5, 0.5) - buttonIcon.Position = UDim2.fromScale(0.25, 0.25) - buttonIcon.Image = image - buttonIcon.Parent = newButton - - local buttonSelectionObject: ImageLabel = Instance.new("ImageLabel") - buttonSelectionObject.BackgroundTransparency = 1 - buttonSelectionObject.Name = "Selection" - buttonSelectionObject.Size = UDim2.fromScale(0.9, 0.9) - buttonSelectionObject.Position = UDim2.fromScale(0.05, 0.05) - buttonSelectionObject.Image = "rbxasset://textures/ui/Keyboard/close_button_selection.png" - newButton.SelectionImageObject = buttonSelectionObject - - return newButton, buttonIcon, buttonSelectionObject -end - --- Make the main frame, which (mostly) covers the screen -MainFrame = Instance.new("Frame") -MainFrame.BackgroundTransparency = 1 -MainFrame.Name = "Backpack" -MainFrame.Size = UDim2.fromScale(1, 1) -MainFrame.Visible = false -MainFrame.Parent = BackpackGui - --- Make the HotbarFrame, which holds only the Hotbar Slots -HotbarFrame = Instance.new("Frame") -HotbarFrame.BackgroundTransparency = 1 -HotbarFrame.Name = "Hotbar" -HotbarFrame.Size = UDim2.fromScale(1, 1) -HotbarFrame.Parent = MainFrame - --- Make all the Hotbar Slots -for index: number = 1, NumberOfHotbarSlots do - local slot: any = MakeSlot(HotbarFrame, index) - slot.Frame.Visible = false - - if not LowestEmptySlot then - LowestEmptySlot = slot - end -end - -local LeftBumperButton: ImageLabel = Instance.new("ImageLabel") -LeftBumperButton.BackgroundTransparency = 1 -LeftBumperButton.Name = "LeftBumper" -LeftBumperButton.Size = UDim2.fromOffset(40, 40) -LeftBumperButton.Position = UDim2.new(0, -LeftBumperButton.Size.X.Offset, 0.5, -LeftBumperButton.Size.Y.Offset / 2) - -local RightBumperButton: ImageLabel = Instance.new("ImageLabel") -RightBumperButton.BackgroundTransparency = 1 -RightBumperButton.Name = "RightBumper" -RightBumperButton.Size = UDim2.fromOffset(40, 40) -RightBumperButton.Position = UDim2.new(1, 0, 0.5, -RightBumperButton.Size.Y.Offset / 2) - --- Make the Inventory, which holds the ScrollingFrame, the header, and the search box -InventoryFrame = Instance.new("Frame") -InventoryFrame.Name = "Inventory" -InventoryFrame.Size = UDim2.fromScale(1, 1) -InventoryFrame.BackgroundTransparency = BACKGROUND_TRANSPARENCY -InventoryFrame.BackgroundColor3 = BACKGROUND_COLOR -InventoryFrame.Active = true -InventoryFrame.Visible = false -InventoryFrame.Parent = MainFrame - --- Add corners to the InventoryFrame -local corner: UICorner = Instance.new("UICorner") -corner.Name = "Corner" -corner.CornerRadius = BACKGROUND_CORNER_RADIUS -corner.Parent = InventoryFrame - -VRInventorySelector = Instance.new("TextButton") -VRInventorySelector.Name = "VRInventorySelector" -VRInventorySelector.Position = UDim2.new(0, 0, 0, 0) -VRInventorySelector.Size = UDim2.fromScale(1, 1) -VRInventorySelector.BackgroundTransparency = 1 -VRInventorySelector.Text = "" -VRInventorySelector.Parent = InventoryFrame - -local selectorImage: ImageLabel = Instance.new("ImageLabel") -selectorImage.BackgroundTransparency = 1 -selectorImage.Name = "Selector" -selectorImage.Size = UDim2.fromScale(1, 1) -selectorImage.Image = "rbxasset://textures/ui/Keyboard/key_selection_9slice.png" -selectorImage.ScaleType = Enum.ScaleType.Slice -selectorImage.SliceCenter = Rect.new(12, 12, 52, 52) -selectorImage.Visible = false -VRInventorySelector.SelectionImageObject = selectorImage - -VRInventorySelector.MouseButton1Click:Connect(function(): () - vrMoveSlotToInventory() -end) - --- Make the ScrollingFrame, which holds the rest of the Slots (however many) -ScrollingFrame = Instance.new("ScrollingFrame") -ScrollingFrame.BackgroundTransparency = 1 -ScrollingFrame.Name = "ScrollingFrame" -ScrollingFrame.Size = UDim2.fromScale(1, 1) -ScrollingFrame.Selectable = false -ScrollingFrame.ScrollingDirection = Enum.ScrollingDirection.Y -ScrollingFrame.BorderSizePixel = 0 -ScrollingFrame.ScrollBarThickness = 8 -ScrollingFrame.ScrollBarImageColor3 = Color3.new(1, 1, 1) -ScrollingFrame.VerticalScrollBarInset = Enum.ScrollBarInset.ScrollBar -ScrollingFrame.CanvasSize = UDim2.new(0, 0, 0, 0) -ScrollingFrame.Parent = InventoryFrame - -UIGridFrame = Instance.new("Frame") -UIGridFrame.BackgroundTransparency = 1 -UIGridFrame.Name = "UIGridFrame" -UIGridFrame.Selectable = false -UIGridFrame.Size = UDim2.new(1, -(ICON_BUFFER_PIXELS * 2), 1, 0) -UIGridFrame.Position = UDim2.fromOffset(ICON_BUFFER_PIXELS, 0) -UIGridFrame.Parent = ScrollingFrame - -UIGridLayout = Instance.new("UIGridLayout") -UIGridLayout.SortOrder = Enum.SortOrder.LayoutOrder -UIGridLayout.CellSize = UDim2.fromOffset(ICON_SIZE_PIXELS, ICON_SIZE_PIXELS) -UIGridLayout.CellPadding = UDim2.fromOffset(ICON_BUFFER_PIXELS, ICON_BUFFER_PIXELS) -UIGridLayout.Parent = UIGridFrame - -ScrollUpInventoryButton = MakeVRRoundButton("ScrollUpButton", "rbxasset://textures/ui/Backpack/ScrollUpArrow.png") -ScrollUpInventoryButton.Size = UDim2.fromOffset(34, 34) -ScrollUpInventoryButton.Position = - UDim2.new(0.5, -ScrollUpInventoryButton.Size.X.Offset / 2, 0, INVENTORY_HEADER_SIZE + 3) -ScrollUpInventoryButton.Icon.Position = ScrollUpInventoryButton.Icon.Position - UDim2.fromOffset(0, 2) -ScrollUpInventoryButton.MouseButton1Click:Connect(function(): () - ScrollingFrame.CanvasPosition = Vector2.new( - ScrollingFrame.CanvasPosition.X, - Clamp( - 0, - ScrollingFrame.CanvasSize.Y.Offset - ScrollingFrame.AbsoluteWindowSize.Y, - ScrollingFrame.CanvasPosition.Y - (ICON_BUFFER_PIXELS + ICON_SIZE_PIXELS) - ) - ) -end) - -ScrollDownInventoryButton = MakeVRRoundButton("ScrollDownButton", "rbxasset://textures/ui/Backpack/ScrollUpArrow.png") -ScrollDownInventoryButton.Rotation = 180 -ScrollDownInventoryButton.Icon.Position = ScrollDownInventoryButton.Icon.Position - UDim2.fromOffset(0, 2) -ScrollDownInventoryButton.Size = UDim2.fromOffset(34, 34) -ScrollDownInventoryButton.Position = - UDim2.new(0.5, -ScrollDownInventoryButton.Size.X.Offset / 2, 1, -ScrollDownInventoryButton.Size.Y.Offset - 3) -ScrollDownInventoryButton.MouseButton1Click:Connect(function(): () - ScrollingFrame.CanvasPosition = Vector2.new( - ScrollingFrame.CanvasPosition.X, - Clamp( - 0, - ScrollingFrame.CanvasSize.Y.Offset - ScrollingFrame.AbsoluteWindowSize.Y, - ScrollingFrame.CanvasPosition.Y + (ICON_BUFFER_PIXELS + ICON_SIZE_PIXELS) - ) - ) -end) - -ScrollingFrame.Changed:Connect(function(prop: string): () - if prop == "AbsoluteWindowSize" or prop == "CanvasPosition" or prop == "CanvasSize" then - local canScrollUp: boolean = ScrollingFrame.CanvasPosition.Y ~= 0 - local canScrollDown: boolean = ScrollingFrame.CanvasPosition.Y - < ScrollingFrame.CanvasSize.Y.Offset - ScrollingFrame.AbsoluteWindowSize.Y - - ScrollUpInventoryButton.Visible = canScrollUp - ScrollDownInventoryButton.Visible = canScrollDown - end -end) - --- Position the frames and sizes for the Backpack GUI elements -UpdateBackpackLayout() - ---Make the gamepad hint frame -local gamepadHintsFrame: Frame = Instance.new("Frame") -gamepadHintsFrame.Name = "GamepadHintsFrame" -gamepadHintsFrame.Size = UDim2.fromOffset(HotbarFrame.Size.X.Offset, (IsTenFootInterface and 95 or 60)) -gamepadHintsFrame.BackgroundTransparency = BACKGROUND_TRANSPARENCY -gamepadHintsFrame.BackgroundColor3 = BACKGROUND_COLOR -gamepadHintsFrame.Visible = false -gamepadHintsFrame.Parent = MainFrame - -local gamepadHintsFrameLayout: UIListLayout = Instance.new("UIListLayout") -gamepadHintsFrameLayout.Name = "Layout" -gamepadHintsFrameLayout.Padding = UDim.new(0, 25) -gamepadHintsFrameLayout.FillDirection = Enum.FillDirection.Horizontal -gamepadHintsFrameLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center -gamepadHintsFrameLayout.SortOrder = Enum.SortOrder.LayoutOrder -gamepadHintsFrameLayout.Parent = gamepadHintsFrame - -local gamepadHintsFrameCorner: UICorner = Instance.new("UICorner") -gamepadHintsFrameCorner.Name = "Corner" -gamepadHintsFrameCorner.CornerRadius = BACKGROUND_CORNER_RADIUS -gamepadHintsFrameCorner.Parent = gamepadHintsFrame - -local function addGamepadHint(hintImageString: string, hintTextString: string): () - local hintFrame: Frame = Instance.new("Frame") - hintFrame.Name = "HintFrame" - hintFrame.AutomaticSize = Enum.AutomaticSize.XY - hintFrame.BackgroundTransparency = 1 - hintFrame.Parent = gamepadHintsFrame - - local hintLayout: UIListLayout = Instance.new("UIListLayout") - hintLayout.Name = "Layout" - hintLayout.Padding = (IsTenFootInterface and UDim.new(0, 20) or UDim.new(0, 12)) - hintLayout.FillDirection = Enum.FillDirection.Horizontal - hintLayout.SortOrder = Enum.SortOrder.LayoutOrder - hintLayout.VerticalAlignment = Enum.VerticalAlignment.Center - hintLayout.Parent = hintFrame - - local hintImage: ImageLabel = Instance.new("ImageLabel") - hintImage.Name = "HintImage" - hintImage.Size = (IsTenFootInterface and UDim2.fromOffset(60, 60) or UDim2.fromOffset(30, 30)) - hintImage.BackgroundTransparency = 1 - hintImage.Image = hintImageString - hintImage.Parent = hintFrame - - local hintText: TextLabel = Instance.new("TextLabel") - hintText.Name = "HintText" - hintText.AutomaticSize = Enum.AutomaticSize.XY - hintText.FontFace = Font.new(FONT_FAMILY.Family, Enum.FontWeight.Medium, Enum.FontStyle.Normal) - hintText.TextSize = (IsTenFootInterface and 32 or 19) - hintText.BackgroundTransparency = 1 - hintText.Text = hintTextString - hintText.TextColor3 = Color3.new(1, 1, 1) - hintText.TextXAlignment = Enum.TextXAlignment.Left - hintText.TextYAlignment = Enum.TextYAlignment.Center - hintText.TextWrapped = true - hintText.Parent = hintFrame - - local textSizeConstraint: UITextSizeConstraint = Instance.new("UITextSizeConstraint") - textSizeConstraint.MaxTextSize = hintText.TextSize - textSizeConstraint.Parent = hintText -end - -addGamepadHint(UserInputService:GetImageForKeyCode(Enum.KeyCode.ButtonX), "Remove From Hotbar") -addGamepadHint(UserInputService:GetImageForKeyCode(Enum.KeyCode.ButtonA), "Select/Swap") -addGamepadHint(UserInputService:GetImageForKeyCode(Enum.KeyCode.ButtonB), "Close Backpack") - -local function resizeGamepadHintsFrame(): () - gamepadHintsFrame.Size = - UDim2.new(HotbarFrame.Size.X.Scale, HotbarFrame.Size.X.Offset, 0, (IsTenFootInterface and 95 or 60)) - gamepadHintsFrame.Position = UDim2.new( - HotbarFrame.Position.X.Scale, - HotbarFrame.Position.X.Offset, - InventoryFrame.Position.Y.Scale, - InventoryFrame.Position.Y.Offset - gamepadHintsFrame.Size.Y.Offset - ICON_BUFFER_PIXELS - ) - - local spaceTaken: number = 0 - - local gamepadHints: { Instance } = gamepadHintsFrame:GetChildren() - local filteredGamepadHints: any = {} - - for _, child: Instance in pairs(gamepadHints) do - if child:IsA("GuiObject") then - table.insert(filteredGamepadHints, child) - end - end - - --First get the total space taken by all the hints - for guiObjects = 1, #filteredGamepadHints do - if filteredGamepadHints[guiObjects]:IsA("GuiObject") then - filteredGamepadHints[guiObjects].Size = UDim2.new(1, 0, 1, -5) - filteredGamepadHints[guiObjects].Position = UDim2.new(0, 0, 0, 0) - spaceTaken = spaceTaken - + ( - filteredGamepadHints[guiObjects].HintText.Position.X.Offset - + filteredGamepadHints[guiObjects].HintText.TextBounds.X - ) - end - end - - --The space between all the frames should be equal - local spaceBetweenElements: number = (gamepadHintsFrame.AbsoluteSize.X - spaceTaken) / (#filteredGamepadHints - 1) - for i: number = 1, #filteredGamepadHints do - filteredGamepadHints[i].Position = ( - i == 1 and UDim2.new(0, 0, 0, 0) - or UDim2.new( - 0, - filteredGamepadHints[i - 1].Position.X.Offset - + filteredGamepadHints[i - 1].Size.X.Offset - + spaceBetweenElements, - 0, - 0 - ) - ) - filteredGamepadHints[i].Size = UDim2.new( - 0, - (filteredGamepadHints[i].HintText.Position.X.Offset + filteredGamepadHints[i].HintText.TextBounds.X), - 1, - -5 - ) - end -end - -local searchFrame: Frame = Instance.new("Frame") -do -- Search stuff - searchFrame.Name = "Search" - searchFrame.BackgroundColor3 = SEARCH_BACKGROUND_COLOR - searchFrame.BackgroundTransparency = SEARCH_BACKGROUND_TRANSPARENCY - searchFrame.Size = UDim2.new( - 0, - SEARCH_WIDTH_PIXELS - (SEARCH_BUFFER_PIXELS * 2), - 0, - INVENTORY_HEADER_SIZE - (SEARCH_BUFFER_PIXELS * 2) - ) - searchFrame.Position = UDim2.new(1, -searchFrame.Size.X.Offset - SEARCH_BUFFER_PIXELS, 0, SEARCH_BUFFER_PIXELS) - searchFrame.Parent = InventoryFrame - - local searchFrameCorner: UICorner = Instance.new("UICorner") - searchFrameCorner.Name = "Corner" - searchFrameCorner.CornerRadius = SEARCH_CORNER_RADIUS - searchFrameCorner.Parent = searchFrame - - local searchFrameBorder: UIStroke = Instance.new("UIStroke") - searchFrameBorder.Name = "Border" - searchFrameBorder.Color = SEARCH_BORDER_COLOR - searchFrameBorder.Thickness = SEARCH_BORDER_THICKNESS - searchFrameBorder.Transparency = SEARCH_BORDER_TRANSPARENCY - searchFrameBorder.Parent = searchFrame - - local searchBox: TextBox = Instance.new("TextBox") - searchBox.BackgroundTransparency = 1 - searchBox.Name = "TextBox" - searchBox.Text = "" - searchBox.TextColor3 = TEXT_COLOR - searchBox.TextStrokeTransparency = TEXT_STROKE_TRANSPARENCY - searchBox.TextStrokeColor3 = TEXT_STROKE_COLOR - searchBox.FontFace = Font.new(FONT_FAMILY.Family, Enum.FontWeight.Medium, Enum.FontStyle.Normal) - searchBox.PlaceholderText = SEARCH_TEXT_PLACEHOLDER - searchBox.TextColor3 = TEXT_COLOR - searchBox.TextTransparency = TEXT_STROKE_TRANSPARENCY - searchBox.TextStrokeColor3 = TEXT_STROKE_COLOR - searchBox.ClearTextOnFocus = false - searchBox.TextTruncate = Enum.TextTruncate.AtEnd - searchBox.TextSize = FONT_SIZE - searchBox.TextXAlignment = Enum.TextXAlignment.Left - searchBox.TextYAlignment = Enum.TextYAlignment.Center - searchBox.Size = UDim2.new( - 0, - (SEARCH_WIDTH_PIXELS - (SEARCH_BUFFER_PIXELS * 2)) - (SEARCH_TEXT_OFFSET * 2) - 20, - 0, - INVENTORY_HEADER_SIZE - (SEARCH_BUFFER_PIXELS * 2) - (SEARCH_TEXT_OFFSET * 2) - ) - searchBox.AnchorPoint = Vector2.new(0, 0.5) - searchBox.Position = UDim2.new(0, SEARCH_TEXT_OFFSET, 0.5, 0) - searchBox.ZIndex = 2 - searchBox.Parent = searchFrame - - local xButton: TextButton = Instance.new("TextButton") - xButton.Name = "X" - xButton.Text = "" - xButton.Size = UDim2.fromOffset(30, 30) - xButton.Position = UDim2.new(1, -xButton.Size.X.Offset, 0.5, -xButton.Size.Y.Offset / 2) - xButton.ZIndex = 4 - xButton.Visible = false - xButton.BackgroundTransparency = 1 - xButton.Parent = searchFrame - - local xImage: ImageButton = Instance.new("ImageButton") - xImage.Name = "X" - xImage.Image = SEARCH_IMAGE_X - xImage.BackgroundTransparency = 1 - xImage.Size = UDim2.new( - 0, - searchFrame.Size.Y.Offset - (SEARCH_BUFFER_PIXELS * 4), - 0, - searchFrame.Size.Y.Offset - (SEARCH_BUFFER_PIXELS * 4) - ) - xImage.AnchorPoint = Vector2.new(0.5, 0.5) - xImage.Position = UDim2.fromScale(0.5, 0.5) - xImage.ZIndex = 1 - xImage.BorderSizePixel = 0 - xImage.Parent = xButton - - local function search(): () - local terms: { [string]: boolean } = {} - for word: string in searchBox.Text:gmatch("%S+") do - terms[word:lower()] = true - end - - local hitTable = {} - for i: number = NumberOfHotbarSlots + 1, #Slots do -- Only search inventory slots - local slot = Slots[i] - local hits: any = slot:CheckTerms(terms) - table.insert(hitTable, { slot, hits }) - slot.Frame.Visible = false - slot.Frame.Parent = InventoryFrame - end - - table.sort(hitTable, function(left: any, right: any): boolean - return left[2] > right[2] - end) - ViewingSearchResults = true - - local hitCount: number = 0 - for _, data in ipairs(hitTable) do - local slot, hits: any = data[1], data[2] - if hits > 0 then - slot.Frame.Visible = true - slot.Frame.Parent = UIGridFrame - slot.Frame.LayoutOrder = NumberOfHotbarSlots + hitCount - hitCount = hitCount + 1 - end - end - - ScrollingFrame.CanvasPosition = Vector2.new(0, 0) - UpdateScrollingFrameCanvasSize() - - xButton.ZIndex = 3 - end - - local function clearResults(): () - if xButton.ZIndex > 0 then - ViewingSearchResults = false - for i: number = NumberOfHotbarSlots + 1, #Slots do - local slot = Slots[i] - slot.Frame.LayoutOrder = slot.Index - slot.Frame.Parent = UIGridFrame - slot.Frame.Visible = true - end - xButton.ZIndex = 0 - end - UpdateScrollingFrameCanvasSize() - end - - local function reset(): () - clearResults() - searchBox.Text = "" - end - - local function onChanged(property: string): () - if property == "Text" then - local text: string = searchBox.Text - if text == "" then - searchBox.TextTransparency = TEXT_STROKE_TRANSPARENCY - clearResults() - elseif text ~= SEARCH_TEXT then - searchBox.TextTransparency = 0 - search() - end - xButton.Visible = text ~= "" and text ~= SEARCH_TEXT - end - end - - local function focusLost(enterPressed: boolean): () - if enterPressed then - --TODO: Could optimize - search() - end - end - - xButton.MouseButton1Click:Connect(reset) - searchBox.Changed:Connect(onChanged) - searchBox.FocusLost:Connect(focusLost) - - BackpackScript.StateChanged.Event:Connect(function(isNowOpen: boolean): () - -- InventoryIcon:getInstance("iconButton").Modal = isNowOpen -- Allows free mouse movement even in first person - - if not isNowOpen then - reset() - end - end) - - HotkeyFns[Enum.KeyCode.Escape.Value] = function(isProcessed: any): () - if isProcessed then -- Pressed from within a TextBox - reset() - end - end - local function detectGamepad(lastInputType: Enum.UserInputType): () - if lastInputType == Enum.UserInputType.Gamepad1 and not UserInputService.VREnabled then - searchFrame.Visible = false - else - searchFrame.Visible = true - end - end - UserInputService.LastInputTypeChanged:Connect(detectGamepad) -end - --- When menu is opend, disable backpack -GuiService.MenuOpened:Connect(function(): () - BackpackGui.Enabled = false - inventoryIcon:setEnabled(false) -end) - --- When menu is closed, enable backpack -GuiService.MenuClosed:Connect(function(): () - BackpackGui.Enabled = true - inventoryIcon:setEnabled(true) -end) - -do -- Make the Inventory expand/collapse arrow (unless TopBar) - -- selene: allow(unused_variable) - local removeHotBarSlot = function(name: string, state: Enum.UserInputState, input: InputObject): () - if state ~= Enum.UserInputState.Begin then - return - end - if not GuiService.SelectedObject then - return - end - - for i: number = 1, NumberOfHotbarSlots do - if Slots[i].Frame == GuiService.SelectedObject and Slots[i].Tool then - Slots[i]:MoveToInventory() - return - end - end - end - - local function openClose(): () - if not next(Dragging) then -- Only continue if nothing is being dragged - InventoryFrame.Visible = not InventoryFrame.Visible - local nowOpen: boolean = InventoryFrame.Visible - AdjustHotbarFrames() - HotbarFrame.Active = not HotbarFrame.Active - for i: number = 1, NumberOfHotbarSlots do - Slots[i]:SetClickability(not nowOpen) - end - end - - if InventoryFrame.Visible then - if GamepadEnabled then - if GAMEPAD_INPUT_TYPES[UserInputService:GetLastInputType()] then - resizeGamepadHintsFrame() - gamepadHintsFrame.Visible = not UserInputService.VREnabled - end - enableGamepadInventoryControl() - end - if BackpackPanel and VRService.VREnabled then - BackpackPanel:SetVisible(true) - BackpackPanel:RequestPositionUpdate() - end - else - if GamepadEnabled then - gamepadHintsFrame.Visible = false - end - disableGamepadInventoryControl() - end - - if InventoryFrame.Visible then - ContextActionService:BindAction("BackpackRemoveSlot", removeHotBarSlot, false, Enum.KeyCode.ButtonX) - else - ContextActionService:UnbindAction("BackpackRemoveSlot") - end - - BackpackScript.IsOpen = InventoryFrame.Visible - BackpackScript.StateChanged:Fire(InventoryFrame.Visible) - end - - StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false) - BackpackScript.OpenClose = openClose -- Exposed -end - --- Now that we're done building the GUI, we Connect to all the major events - --- Wait for the player if LocalPlayer wasn't ready earlier -while not Player do - task.wait() - Player = Players.LocalPlayer -end - --- Listen to current and all future characters of our player -Player.CharacterAdded:Connect(OnCharacterAdded) -if Player.Character then - OnCharacterAdded(Player.Character) -end - -do -- Hotkey stuff - -- Listen to key down - UserInputService.InputBegan:Connect(OnInputBegan) - - -- Listen to ANY TextBox gaining or losing focus, for disabling all hotkeys - UserInputService.TextBoxFocused:Connect(function(): () - TextBoxFocused = true - end) - UserInputService.TextBoxFocusReleased:Connect(function(): () - TextBoxFocused = false - end) - - -- Manual unequip for HopperBins on drop button pressed - HotkeyFns[DROP_HOTKEY_VALUE] = function(): () --NOTE: HopperBin - if ActiveHopper then - UnequipAllTools() - end - end - - -- Listen to keyboard status, for showing/hiding hotkey labels - UserInputService.LastInputTypeChanged:Connect(OnUISChanged) - OnUISChanged() - - -- Listen to gamepad status, for allowing gamepad style selection/equip - if UserInputService:GetGamepadConnected(Enum.UserInputType.Gamepad1) then - gamepadConnected() - end - UserInputService.GamepadConnected:Connect(function(gamepadEnum: Enum.UserInputType): () - if gamepadEnum == Enum.UserInputType.Gamepad1 then - gamepadConnected() - end - end) - UserInputService.GamepadDisconnected:Connect(function(gamepadEnum: Enum.UserInputType): () - if gamepadEnum == Enum.UserInputType.Gamepad1 then - gamepadDisconnected() - end - end) -end - --- Sets whether the backpack is enabled or not -function BackpackScript:SetBackpackEnabled(Enabled: boolean): () - BackpackEnabled = Enabled -end - --- Returns if the backpack's inventory is open -function BackpackScript:IsOpened(): boolean - return BackpackScript.IsOpen -end - --- Returns on if the backpack is enabled or not -function BackpackScript:GetBackpackEnabled(): boolean - return BackpackEnabled -end --- Returns the BindableEvent for when the backpack state changes -function BackpackScript:GetStateChangedEvent(): BindableEvent - return BackpackScript.StateChanged -end +local React = require("./react") +local ReactRoblox = require("./react-roblox") --- Update every heartbeat the icon state -RunService.Heartbeat:Connect(function(): () - OnIconChanged(BackpackEnabled) -end) +local Hotbar = require("@self/Components/Hotbar") --- Update the transparency of the backpack based on GuiService.PreferredTransparency -local function OnPreferredTransparencyChanged(): () - local preferredTransparency: number = GuiService.PreferredTransparency +local player = Players.LocalPlayer :: Player +local playerGui = player.PlayerGui - BACKGROUND_TRANSPARENCY = BACKGROUND_TRANSPARENCY_DEFAULT * preferredTransparency - InventoryFrame.BackgroundTransparency = BACKGROUND_TRANSPARENCY +local handle = Instance.new("ScreenGui") +handle.Name = "SatchelGui" +handle.Parent = playerGui - SLOT_LOCKED_TRANSPARENCY = SLOT_LOCKED_TRANSPARENCY_DEFAULT * preferredTransparency - for _, slot in ipairs(Slots) do - slot.Frame.BackgroundTransparency = SLOT_LOCKED_TRANSPARENCY - end +local styleLink = Instance.new("StyleLink") +styleLink.StyleSheet = script.Design.SatchelStyleSheet +styleLink.Parent = handle - SEARCH_BACKGROUND_TRANSPARENCY = SEARCH_BACKGROUND_TRANSPARENCY_DEFAULT * preferredTransparency - searchFrame.BackgroundTransparency = SEARCH_BACKGROUND_TRANSPARENCY -end -GuiService:GetPropertyChangedSignal("PreferredTransparency"):Connect(OnPreferredTransparencyChanged) +local root = ReactRoblox.createRoot(handle) +root:render(React.createElement(Hotbar), { opened = true }) -return BackpackScript +return {} From 303b4fb19f23b696968d4b771839b43caaa99d53 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 22 Feb 2026 13:18:17 -0800 Subject: [PATCH 029/186] Fix missing style link Signed-off-by: Ryan Luu --- src/init.luau | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/init.luau b/src/init.luau index 3980b8da..366480f3 100644 --- a/src/init.luau +++ b/src/init.luau @@ -14,11 +14,14 @@ local handle = Instance.new("ScreenGui") handle.Name = "SatchelGui" handle.Parent = playerGui -local styleLink = Instance.new("StyleLink") -styleLink.StyleSheet = script.Design.SatchelStyleSheet -styleLink.Parent = handle - local root = ReactRoblox.createRoot(handle) -root:render(React.createElement(Hotbar), { opened = true }) +root:render(React.createElement(React.Fragment, nil, { + StyleLink = React.createElement("StyleLink", { + StyleSheet = script.Design.SatchelStyleSheet, + }), + Hotbar = React.createElement(Hotbar, { + opened = true, + }), +})) return {} From 486ad88a11c6ddae0f1aa89ac4db7213faa09f6b Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 22 Feb 2026 19:24:21 -0800 Subject: [PATCH 030/186] Add input actions Signed-off-by: Ryan Luu --- src/Bindings/BackpackContext.model.json | 47 +++++++ src/Bindings/HotbarContext.model.json | 180 ++++++++++++++++++++++++ 2 files changed, 227 insertions(+) create mode 100644 src/Bindings/BackpackContext.model.json create mode 100644 src/Bindings/HotbarContext.model.json diff --git a/src/Bindings/BackpackContext.model.json b/src/Bindings/BackpackContext.model.json new file mode 100644 index 00000000..e84b8a4e --- /dev/null +++ b/src/Bindings/BackpackContext.model.json @@ -0,0 +1,47 @@ +{ + "ClassName": "InputContext", + "Properties": { + "Priority": 2000 + }, + "Children": [ + { + "Name": "CloseInventoryAction", + "ClassName": "InputAction", + "Children": [ + { + "Name": "GamepadBinding", + "ClassName": "InputBinding", + "Properties": { + "KeyCode": "ButtonB" + } + } + ] + }, + { + "Name": "RemoveFromHotbarAction", + "ClassName": "InputAction", + "Children": [ + { + "Name": "GamepadBinding", + "ClassName": "InputBinding", + "Properties": { + "KeyCode": "ButtonX" + } + } + ] + }, + { + "Name": "SelectSwapAction", + "ClassName": "InputAction", + "Children": [ + { + "Name": "GamepadBinding", + "ClassName": "InputBinding", + "Properties": { + "KeyCode": "ButtonA" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/src/Bindings/HotbarContext.model.json b/src/Bindings/HotbarContext.model.json new file mode 100644 index 00000000..35ef6372 --- /dev/null +++ b/src/Bindings/HotbarContext.model.json @@ -0,0 +1,180 @@ +{ + "ClassName": "InputContext", + "Properties": { + "Priority": 2000 + }, + "Children": [ + { + "Name": "SlotLeftAction", + "ClassName": "InputAction", + "Children": [ + { + "Name": "GamepadBinding", + "ClassName": "InputBinding", + "Properties": { + "KeyCode": "ButtonL1" + } + } + ] + }, + { + "Name": "SlotRightAction", + "ClassName": "InputAction", + "Children": [ + { + "Name": "GamepadBinding", + "ClassName": "InputBinding", + "Properties": { + "KeyCode": "ButtonR1" + } + } + ] + }, + { + "Name": "SlotOneAction", + "ClassName": "InputAction", + "Children": [ + { + "Name": "KeyBinding", + "ClassName": "InputBinding", + "Properties": { + "KeyCode": "One" + } + } + ] + }, + { + "Name": "SlotTwoAction", + "ClassName": "InputAction", + "Children": [ + { + "Name": "KeyBinding", + "ClassName": "InputBinding", + "Properties": { + "KeyCode": "Two" + } + } + ] + }, + { + "Name": "SlotThreeAction", + "ClassName": "InputAction", + "Children": [ + { + "Name": "KeyBinding", + "ClassName": "InputBinding", + "Properties": { + "KeyCode": "Three" + } + } + ] + }, + { + "Name": "SlotFourAction", + "ClassName": "InputAction", + "Children": [ + { + "Name": "KeyBinding", + "ClassName": "InputBinding", + "Properties": { + "KeyCode": "Four" + } + } + ] + }, + { + "Name": "SlotFiveAction", + "ClassName": "InputAction", + "Children": [ + { + "Name": "KeyBinding", + "ClassName": "InputBinding", + "Properties": { + "KeyCode": "Five" + } + } + ] + }, + { + "Name": "SlotSixAction", + "ClassName": "InputAction", + "Children": [ + { + "Name": "KeyBinding", + "ClassName": "InputBinding", + "Properties": { + "KeyCode": "Six" + } + } + ] + }, + { + "Name": "SlotSevenAction", + "ClassName": "InputAction", + "Children": [ + { + "Name": "KeyBinding", + "ClassName": "InputBinding", + "Properties": { + "KeyCode": "Seven" + } + } + ] + }, + { + "Name": "SlotEightAction", + "ClassName": "InputAction", + "Children": [ + { + "Name": "KeyBinding", + "ClassName": "InputBinding", + "Properties": { + "KeyCode": "Eight" + } + } + ] + }, + { + "Name": "SlotNineAction", + "ClassName": "InputAction", + "Children": [ + { + "Name": "KeyBinding", + "ClassName": "InputBinding", + "Properties": { + "KeyCode": "Nine" + } + } + ] + }, + { + "Name": "SlotZeroAction", + "ClassName": "InputAction", + "Children": [ + { + "Name": "KeyBinding", + "ClassName": "InputBinding", + "Properties": { + "KeyCode": "Zero" + } + } + ] + }, + { + "Name": "ToggleInventoryAction", + "ClassName": "InputAction", + "Properties": { + "Enabled": false + }, + "Children": [ + { + "Name": "KeyBinding", + "ClassName": "InputBinding", + "Properties": { + "KeyCode": "Backquote" + } + } + ] + } + ] +} \ No newline at end of file From a5e0ef65c1664a0ac961c637cc90b7e1985969a1 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 22 Feb 2026 19:31:28 -0800 Subject: [PATCH 031/186] Only ignore build outputs Signed-off-by: Ryan Luu --- .gitignore | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index a8765c27..f3cc969f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,5 @@ # Rojo sourcemap.json -*.rbxl -*.rbxlx -*.rbxm -*.rbxmx -!src/ # Wally Packages/ @@ -12,3 +7,6 @@ DevPackages/ # MkDocs documentation site/ + +# Builds +builds/ \ No newline at end of file From fb7fb59a4aeb838811a57d0f37b07bf631212e2b Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 22 Feb 2026 20:17:54 -0800 Subject: [PATCH 032/186] Don't use require by string Signed-off-by: Ryan Luu --- src/init.luau | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/init.luau b/src/init.luau index 366480f3..0e91b563 100644 --- a/src/init.luau +++ b/src/init.luau @@ -2,10 +2,10 @@ local Players = game:GetService("Players") -local React = require("./react") -local ReactRoblox = require("./react-roblox") +local React = require(script.Parent.react) +local ReactRoblox = require(script.Parent["react-roblox"]) -local Hotbar = require("@self/Components/Hotbar") +local Hotbar = require(script.Components.Hotbar) local player = Players.LocalPlayer :: Player local playerGui = player.PlayerGui From 424997786113e5b51c1f136414acf393c1c30bff Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 22 Feb 2026 20:44:44 -0800 Subject: [PATCH 033/186] Add backpack component Signed-off-by: Ryan Luu --- src/Components/Backpack.luau | 25 ++++++++++++++++++++ src/Components/Backpack.story.luau | 37 ++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 src/Components/Backpack.luau create mode 100644 src/Components/Backpack.story.luau diff --git a/src/Components/Backpack.luau b/src/Components/Backpack.luau new file mode 100644 index 00000000..8c8b6973 --- /dev/null +++ b/src/Components/Backpack.luau @@ -0,0 +1,25 @@ +local React = require(script.Parent.Parent.Parent.react) + +local Hotbar = require(script.Parent.Hotbar) + +export type Props = { + forceGamepadHintVisible: boolean?, + forceKeyboardHintVisible: boolean?, + slots: number?, + tools: { Tool? }?, + opened: boolean?, +} + +local function Backpack(props: Props) + return React.createElement("Frame", { [React.Tag] = "Backpack" }, { + Hotbar = React.createElement(Hotbar, { + forceGamepadHintVisible = props.forceGamepadHintVisible, + forceKeyboardHintVisible = props.forceKeyboardHintVisible, + slots = props.slots, + tools = props.tools, + opened = props.opened, + }), + }) +end + +return Backpack diff --git a/src/Components/Backpack.story.luau b/src/Components/Backpack.story.luau new file mode 100644 index 00000000..d178f5b0 --- /dev/null +++ b/src/Components/Backpack.story.luau @@ -0,0 +1,37 @@ +local React = require(script.Parent.Parent.Parent.react) + +local Backpack = require(script.Parent.Backpack) + +local controls = { + forceGamepadHintVisible = true, + forceKeyboardHintVisible = true, + slots = 10, + toolName = "Sword", + toolImage = "rbxasset://Textures/Sword128.png", + tooltipText = "A classic sword", + toolSlot = 1, + opened = false, +} + +type Props = { + controls: typeof(controls), +} + +return { + summary = "Backpack that holds the hotbar and inventory", + controls = controls, + story = function(props: Props) + local Tool = Instance.new("Tool") + Tool.Name = props.controls.toolName + Tool.TextureId = props.controls.toolImage + Tool.ToolTip = props.controls.tooltipText + + return React.createElement(Backpack, { + forceGamepadHintVisible = props.controls.forceGamepadHintVisible, + forceKeyboardHintVisible = props.controls.forceKeyboardHintVisible, + slots = props.controls.slots, + tools = { [props.controls.toolSlot] = Tool }, + opened = props.controls.opened, + }) + end, +} From c49bbb8615b65611fece1f746a897decd4e7248c Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 22 Feb 2026 20:46:22 -0800 Subject: [PATCH 034/186] Render backpack component Signed-off-by: Ryan Luu --- src/init.luau | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/init.luau b/src/init.luau index 0e91b563..e857918b 100644 --- a/src/init.luau +++ b/src/init.luau @@ -5,7 +5,7 @@ local Players = game:GetService("Players") local React = require(script.Parent.react) local ReactRoblox = require(script.Parent["react-roblox"]) -local Hotbar = require(script.Components.Hotbar) +local Backpack = require(script.Components.Backpack) local player = Players.LocalPlayer :: Player local playerGui = player.PlayerGui @@ -19,7 +19,7 @@ root:render(React.createElement(React.Fragment, nil, { StyleLink = React.createElement("StyleLink", { StyleSheet = script.Design.SatchelStyleSheet, }), - Hotbar = React.createElement(Hotbar, { + Backpack = React.createElement(Backpack, { opened = true, }), })) From 6504b2764d8fd614a232d3ae7577e2df011853f6 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 22 Feb 2026 20:49:31 -0800 Subject: [PATCH 035/186] Enable strict type checking Signed-off-by: Ryan Luu --- src/Components/Backpack.luau | 2 ++ src/Components/Backpack.story.luau | 2 ++ src/Components/Hotbar.luau | 2 ++ src/Components/Hotbar.story.luau | 2 ++ src/Components/HotbarHint.story.luau | 2 ++ src/Components/Slot.story.luau | 2 ++ src/Components/Tooltip.luau | 2 ++ 7 files changed, 14 insertions(+) diff --git a/src/Components/Backpack.luau b/src/Components/Backpack.luau index 8c8b6973..2a241c6e 100644 --- a/src/Components/Backpack.luau +++ b/src/Components/Backpack.luau @@ -1,3 +1,5 @@ +--!strict + local React = require(script.Parent.Parent.Parent.react) local Hotbar = require(script.Parent.Hotbar) diff --git a/src/Components/Backpack.story.luau b/src/Components/Backpack.story.luau index d178f5b0..ca9c1b95 100644 --- a/src/Components/Backpack.story.luau +++ b/src/Components/Backpack.story.luau @@ -1,3 +1,5 @@ +--!strict + local React = require(script.Parent.Parent.Parent.react) local Backpack = require(script.Parent.Backpack) diff --git a/src/Components/Hotbar.luau b/src/Components/Hotbar.luau index ec424e5c..6486e78c 100644 --- a/src/Components/Hotbar.luau +++ b/src/Components/Hotbar.luau @@ -1,3 +1,5 @@ +--!strict + local React = require(script.Parent.Parent.Parent.react) local HotbarHint = require(script.Parent.HotbarHint) diff --git a/src/Components/Hotbar.story.luau b/src/Components/Hotbar.story.luau index bb71b62a..b1f90eb5 100644 --- a/src/Components/Hotbar.story.luau +++ b/src/Components/Hotbar.story.luau @@ -1,3 +1,5 @@ +--!strict + local React = require(script.Parent.Parent.Parent.react) local Hotbar = require(script.Parent.Hotbar) diff --git a/src/Components/HotbarHint.story.luau b/src/Components/HotbarHint.story.luau index 6105f724..8aecd244 100644 --- a/src/Components/HotbarHint.story.luau +++ b/src/Components/HotbarHint.story.luau @@ -1,3 +1,5 @@ +--!strict + local React = require(script.Parent.Parent.Parent.react) local HotbarHint = require(script.Parent.HotbarHint) diff --git a/src/Components/Slot.story.luau b/src/Components/Slot.story.luau index d7d1abd1..fb8d159e 100644 --- a/src/Components/Slot.story.luau +++ b/src/Components/Slot.story.luau @@ -1,3 +1,5 @@ +--!strict + local React = require(script.Parent.Parent.Parent.react) local Slot = require(script.Parent.Slot) diff --git a/src/Components/Tooltip.luau b/src/Components/Tooltip.luau index 860b56d6..c6a2cec1 100644 --- a/src/Components/Tooltip.luau +++ b/src/Components/Tooltip.luau @@ -1,3 +1,5 @@ +--!strict + local React = require(script.Parent.Parent.Parent.react) export type Props = { From e89177f1465e0a53c3b90ca06201fc7f1c104d88 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 23 Feb 2026 12:10:36 -0800 Subject: [PATCH 036/186] Remove loader Signed-off-by: Ryan Luu --- develop.project.json | 2 +- .../{SatchelLoader => }/Satchel/Packages.project.json | 4 ++-- models/{SatchelLoader => }/Satchel/init.luau | 0 models/SatchelLoader/init.client.luau | 11 ----------- 4 files changed, 3 insertions(+), 14 deletions(-) rename models/{SatchelLoader => }/Satchel/Packages.project.json (50%) rename models/{SatchelLoader => }/Satchel/init.luau (100%) delete mode 100644 models/SatchelLoader/init.client.luau diff --git a/develop.project.json b/develop.project.json index c8168d13..9644c99b 100644 --- a/develop.project.json +++ b/develop.project.json @@ -6,7 +6,7 @@ "ReplicatedStorage": { "$className": "ReplicatedStorage", "SatchelLoader": { - "$path": "models/SatchelLoader" + "$path": "models/Satchel" } } } diff --git a/models/SatchelLoader/Satchel/Packages.project.json b/models/Satchel/Packages.project.json similarity index 50% rename from models/SatchelLoader/Satchel/Packages.project.json rename to models/Satchel/Packages.project.json index 84cedaa9..59b65a7c 100644 --- a/models/SatchelLoader/Satchel/Packages.project.json +++ b/models/Satchel/Packages.project.json @@ -1,9 +1,9 @@ { "name": "Packages", "tree": { - "$path": "../../../Packages", + "$path": "../../Packages", "satchel": { - "$path": "../../../src" + "$path": "../../src" } } } \ No newline at end of file diff --git a/models/SatchelLoader/Satchel/init.luau b/models/Satchel/init.luau similarity index 100% rename from models/SatchelLoader/Satchel/init.luau rename to models/Satchel/init.luau diff --git a/models/SatchelLoader/init.client.luau b/models/SatchelLoader/init.client.luau deleted file mode 100644 index 7df44f4a..00000000 --- a/models/SatchelLoader/init.client.luau +++ /dev/null @@ -1,11 +0,0 @@ ---[[ - 💖 Thanks for using Satchel 💖 - - Satchel is a modern open-source alternative to Roblox's default backpack 🎒 - - 📰 DevForum: https://devforum.roblox.com/t/2451549 - 🛍️ Creator Store: https://create.roblox.com/store/asset/13947506401 - 🛝 Playground: https://www.roblox.com/games/13592168150 -]] - -require(script.Satchel) From 3ed2e3f90b536ee46023e857fca77c308ef72101 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 23 Feb 2026 12:13:56 -0800 Subject: [PATCH 037/186] Remove loader references Signed-off-by: Ryan Luu --- develop.project.json | 2 +- docs/installation.md | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/develop.project.json b/develop.project.json index 9644c99b..6ca3f5a7 100644 --- a/develop.project.json +++ b/develop.project.json @@ -5,7 +5,7 @@ "$className": "DataModel", "ReplicatedStorage": { "$className": "ReplicatedStorage", - "SatchelLoader": { + "Satchel": { "$path": "models/Satchel" } } diff --git a/docs/installation.md b/docs/installation.md index a9720cde..0268a590 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -69,13 +69,6 @@ The Creator Store is the easiest way to install Satchel. It is a one-click insta You are expected to already have Wally setup in your Rojo project and basic knowledge on how to use Wally packages. -!!! warning - - Wally does not include the loader script so you need to [`#!lua require()`][require] Satchel to run: - ``` lua title="Satchel Loader" - require(script.Satchel) - ``` - 1. Open your Rojo project in the code editor of your choice. 1. In the `wally.toml` file, add the [latest Wally version for Satchel][Wally]. Your dependencies should look similar to this: From 6a9c7b1f137c441da20bae79d605dfac8f073f9c Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 23 Feb 2026 14:33:14 -0800 Subject: [PATCH 038/186] Return nil Signed-off-by: Ryan Luu --- src/Components/Tooltip.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Tooltip.luau b/src/Components/Tooltip.luau index c6a2cec1..68857db9 100644 --- a/src/Components/Tooltip.luau +++ b/src/Components/Tooltip.luau @@ -9,7 +9,7 @@ export type Props = { local function Tooltip(props: Props) -- Hide tooltip if there is no text if not props.text or props.text == "" then - return + return nil end return React.createElement("TextLabel", { From 2b71060edeedfbebd21062cd8f2e74cee1472ed2 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 23 Feb 2026 16:12:30 -0800 Subject: [PATCH 039/186] Add search bar component Signed-off-by: Ryan Luu --- src/Components/Searchbar.luau | 18 ++++++++++++++++++ src/Components/Searchbar.story.luau | 14 ++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/Components/Searchbar.luau create mode 100644 src/Components/Searchbar.story.luau diff --git a/src/Components/Searchbar.luau b/src/Components/Searchbar.luau new file mode 100644 index 00000000..80565a17 --- /dev/null +++ b/src/Components/Searchbar.luau @@ -0,0 +1,18 @@ +--!strict + +local React = require(script.Parent.Parent.Parent.react) + +export type Props = { + size: UDim2?, +} + +local function Searchbar(props: Props) + return React.createElement("TextBox", { + Size = props.size, + [React.Tag] = "Searchbar", + }, { + Clear = React.createElement("ImageButton"), + }) +end + +return Searchbar diff --git a/src/Components/Searchbar.story.luau b/src/Components/Searchbar.story.luau new file mode 100644 index 00000000..e03b0359 --- /dev/null +++ b/src/Components/Searchbar.story.luau @@ -0,0 +1,14 @@ +--!strict + +local React = require(script.Parent.Parent.Parent.react) + +local Searchbar = require(script.Parent.Searchbar) + +return { + summary = "Searchbar for searching items in the inventory", + story = function() + return React.createElement(Searchbar, { + size = UDim2.fromOffset(190, 30), + }) + end, +} From 7d4c29e85339c28ed63a56a3acc97213a2a18ca1 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 23 Feb 2026 16:12:47 -0800 Subject: [PATCH 040/186] Improve formatting Signed-off-by: Ryan Luu --- src/Components/Backpack.luau | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Components/Backpack.luau b/src/Components/Backpack.luau index 2a241c6e..7b17cdc8 100644 --- a/src/Components/Backpack.luau +++ b/src/Components/Backpack.luau @@ -13,7 +13,9 @@ export type Props = { } local function Backpack(props: Props) - return React.createElement("Frame", { [React.Tag] = "Backpack" }, { + return React.createElement("Frame", { + [React.Tag] = "Backpack", + }, { Hotbar = React.createElement(Hotbar, { forceGamepadHintVisible = props.forceGamepadHintVisible, forceKeyboardHintVisible = props.forceKeyboardHintVisible, From 98960436adb3d6ebbeff3a2dbd09390888038940 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 23 Feb 2026 16:19:06 -0800 Subject: [PATCH 041/186] Fix searchbar capitalization Signed-off-by: Ryan Luu --- src/Design.rbxmx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Design.rbxmx b/src/Design.rbxmx index dd079b31..0c198d7f 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -530,11 +530,11 @@ AAAABAAAAFNpemUKAAAAACUAAAAAAAAAJQAAAA==]]> FgAAAEJhY2tncm91bmRUcmFuc3BhcmVuY3kCIAAAACRDb250YWluZXJCYWNrZ3JvdW5kVHJh bnNwYXJlbmN5]]> - .Container,.SearchBar + .Container,.Searchbar 0 false - .Container,.SearchBar + .Container,.Searchbar -1 @@ -686,11 +686,11 @@ b2xvcjMCEAAAACRTZWFyY2hUZXh0Q29sb3IIAAAAVGV4dFNpemUCDwAAACRTZWFyY2hUZXh0 U2l6ZRYAAABUZXh0U3Ryb2tlVHJhbnNwYXJlbmN5Ah0AAAAkU2VhcmNoVGV4dFN0cm9rZVRy YW5zcGFyZW5jeQ4AAABUZXh0WEFsaWdubWVudBUOAAAAVGV4dFhBbGlnbm1lbnQAAAAA]]> - .SearchBar + .Searchbar 0 false - .SearchBar + .Searchbar -1 From 1083d7b93385d9b40702c51deef6dc3a2478c1f9 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Tue, 24 Feb 2026 00:11:31 -0800 Subject: [PATCH 042/186] Add inventory component Signed-off-by: Ryan Luu --- src/Components/Inventory.luau | 25 +++++++++++++++++++++++++ src/Components/Inventory.story.luau | 14 ++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/Components/Inventory.luau create mode 100644 src/Components/Inventory.story.luau diff --git a/src/Components/Inventory.luau b/src/Components/Inventory.luau new file mode 100644 index 00000000..638a6b5d --- /dev/null +++ b/src/Components/Inventory.luau @@ -0,0 +1,25 @@ +--!strict + +local React = require(script.Parent.Parent.Parent.react) + +local Searchbar = require(script.Parent.Searchbar) + +export type Props = { + forceGamepadHintVisible: boolean?, + size: UDim2?, + slots: number?, + tools: { Tool? }?, + opened: boolean?, +} + +local function Inventory(props: Props) + return React.createElement("Frame", { + Size = props.size, + [React.Tag] = "Inventory", + }, { + SearchBox = React.createElement(Searchbar), + SlotFrame = React.createElement("ScrollingFrame"), + }) +end + +return Inventory diff --git a/src/Components/Inventory.story.luau b/src/Components/Inventory.story.luau new file mode 100644 index 00000000..941fc195 --- /dev/null +++ b/src/Components/Inventory.story.luau @@ -0,0 +1,14 @@ +--!strict + +local React = require(script.Parent.Parent.Parent.react) + +local Inventory = require(script.Parent.Inventory) + +return { + summary = "Inventory for displaying items not in the hotbar", + story = function() + return React.createElement(Inventory, { + size = UDim2.new(1, 0, 0, 320), + }) + end, +} From b6c585c91ac2d4f4d18dfb0861b5be0ba1c2ae26 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Tue, 24 Feb 2026 00:35:26 -0800 Subject: [PATCH 043/186] Update summaries --- src/Components/Hotbar.story.luau | 2 +- src/Components/HotbarHint.story.luau | 3 ++- src/Components/Inventory.story.luau | 2 +- src/Components/Searchbar.story.luau | 2 +- src/Components/Slot.story.luau | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Components/Hotbar.story.luau b/src/Components/Hotbar.story.luau index b1f90eb5..e6c0b03d 100644 --- a/src/Components/Hotbar.story.luau +++ b/src/Components/Hotbar.story.luau @@ -21,7 +21,7 @@ type Props = { } return { - summary = "Hotbar component that holds hotbar slots and hints", + summary = "Hotbar on the bottom of the screen that shows equipped tools and hints for equipping", controls = controls, story = function(props: Props) local tool = Instance.new("Tool") diff --git a/src/Components/HotbarHint.story.luau b/src/Components/HotbarHint.story.luau index 8aecd244..dd6fb9fa 100644 --- a/src/Components/HotbarHint.story.luau +++ b/src/Components/HotbarHint.story.luau @@ -13,7 +13,8 @@ type Props = { } return { - summary = "Hint for switching to a hotbar slot, displayed when gamepad is preferred or forced visible", + name = "Hotbar Hint", + summary = "Hint shown in the hotbar to show how to equip slots", controls = controls, story = function(props: Props) return React.createElement(HotbarHint, { diff --git a/src/Components/Inventory.story.luau b/src/Components/Inventory.story.luau index 941fc195..26e745bf 100644 --- a/src/Components/Inventory.story.luau +++ b/src/Components/Inventory.story.luau @@ -5,7 +5,7 @@ local React = require(script.Parent.Parent.Parent.react) local Inventory = require(script.Parent.Inventory) return { - summary = "Inventory for displaying items not in the hotbar", + summary = "Toggleable inventory for displaying items not in the hotbar", story = function() return React.createElement(Inventory, { size = UDim2.new(1, 0, 0, 320), diff --git a/src/Components/Searchbar.story.luau b/src/Components/Searchbar.story.luau index e03b0359..f2ba6f87 100644 --- a/src/Components/Searchbar.story.luau +++ b/src/Components/Searchbar.story.luau @@ -5,7 +5,7 @@ local React = require(script.Parent.Parent.Parent.react) local Searchbar = require(script.Parent.Searchbar) return { - summary = "Searchbar for searching items in the inventory", + summary = "Search for items in the inventory", story = function() return React.createElement(Searchbar, { size = UDim2.fromOffset(190, 30), diff --git a/src/Components/Slot.story.luau b/src/Components/Slot.story.luau index fb8d159e..db7cb1b0 100644 --- a/src/Components/Slot.story.luau +++ b/src/Components/Slot.story.luau @@ -19,7 +19,7 @@ type Props = { } return { - summary = "Text button that can hold a tool", + summary = "Slot representing a single item in the hotbar or inventory, showing the tool and hints for equipping", controls = controls, story = function(props: Props) local Tool = Instance.new("Tool") From 76b681af98f7d10b08ec00dcc189f99e60ee201c Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Tue, 24 Feb 2026 00:39:15 -0800 Subject: [PATCH 044/186] Fix issues with requires --- .vscode/settings.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index bc412731..edc617ac 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,5 +10,6 @@ "tag:yaml.org,2002:python/name:material.extensions.emoji.twemoji", "tag:yaml.org,2002:python/name:pymdownx.superfences.fence_code_format", "tag:yaml.org,2002:python/object/apply:pymdownx.slugs.slugify mapping" - ] + ], + "luau-lsp.sourcemap.rojoProjectFile": "develop.project.json" } \ No newline at end of file From 2c7c5bf09735672eace875b49a779da6bfa84b3f Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Tue, 24 Feb 2026 00:41:50 -0800 Subject: [PATCH 045/186] Use package --- .vscode/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index edc617ac..7bf33192 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,5 +11,5 @@ "tag:yaml.org,2002:python/name:pymdownx.superfences.fence_code_format", "tag:yaml.org,2002:python/object/apply:pymdownx.slugs.slugify mapping" ], - "luau-lsp.sourcemap.rojoProjectFile": "develop.project.json" + "luau-lsp.sourcemap.rojoProjectFile": "package.project.json" } \ No newline at end of file From c5ead80245d80767a0a0a91e0ba8247a1ff910f1 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Tue, 24 Feb 2026 01:13:34 -0800 Subject: [PATCH 046/186] Fix incorrect env Signed-off-by: Ryan Luu --- .github/workflows/documentation.yml | 3 +++ .github/workflows/release.yml | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 2fe4df20..bf5ff647 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -13,6 +13,9 @@ on: permissions: contents: write +env: + VERSION: 1.x + jobs: deploy: runs-on: ubuntu-latest diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b3c64084..c5afc0f4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,9 +5,6 @@ on: tags: - "v*.*.*" -env: - VERSION: 1.x - permissions: contents: write From 03305c4570cb8ebaf156fd7e554c2022f94b3dc5 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Tue, 24 Feb 2026 14:34:55 -0800 Subject: [PATCH 047/186] Remove old attributes Signed-off-by: Ryan Luu --- src/init.meta.json | 39 --------------------------------------- 1 file changed, 39 deletions(-) delete mode 100644 src/init.meta.json diff --git a/src/init.meta.json b/src/init.meta.json deleted file mode 100644 index 6efa65d8..00000000 --- a/src/init.meta.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "properties": { - "Attributes": { - "BackgroundColor3": { - "Color3": [0.0980392157, 0.105882353, 0.11372549] - }, - "BackgroundTransparency": { - "Float32": 0.3 - }, - "CornerRadius": { - "UDim": [0, 8] - }, - "EquipBorderColor3": { - "Color3": [1, 1, 1] - }, - "EquipBorderSizePixel": { - "Float32": 5 - }, - "InsetIconPadding": { - "Bool": true - }, - "OutlineEquipBorder": { - "Bool": true - }, - "TextColor3": { - "Color3": [1, 1, 1] - }, - "TextSize": { - "Float32": 16 - }, - "TextStrokeColor3": { - "Color3": [0, 0, 0] - }, - "TextStrokeTransparency": { - "Float32": 0.5 - } - } - } -} From 48840eef73c901bfdc71d5c6c449cf4808dcb9c9 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 9 Mar 2026 00:43:33 -0700 Subject: [PATCH 048/186] Combine opened and unlocked prop logic Signed-off-by: Ryan Luu --- src/Components/Hotbar.luau | 3 +-- src/Components/Hotbar.story.luau | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Components/Hotbar.luau b/src/Components/Hotbar.luau index 6486e78c..4a690db0 100644 --- a/src/Components/Hotbar.luau +++ b/src/Components/Hotbar.luau @@ -10,7 +10,6 @@ export type Props = { forceKeyboardHintVisible: boolean?, slots: number?, tools: { Tool? }?, - unlocked: boolean?, opened: boolean?, } @@ -21,7 +20,7 @@ local function Hotbar(props: Props) for slotNumber = 1, slotCount do local tool = props.tools and props.tools[slotNumber] - local slotUnlocked = props.unlocked and tool ~= nil + local slotUnlocked = props.opened and tool ~= nil -- Only show slots if the hotbar is opened or if there is a tool in the slot if props.opened or tool then diff --git a/src/Components/Hotbar.story.luau b/src/Components/Hotbar.story.luau index e6c0b03d..b5f37c2e 100644 --- a/src/Components/Hotbar.story.luau +++ b/src/Components/Hotbar.story.luau @@ -12,7 +12,6 @@ local controls = { toolImage = "rbxasset://Textures/Sword128.png", tooltipText = "A classic sword", toolSlot = 1, - unlocked = false, opened = true, } @@ -37,7 +36,6 @@ return { forceKeyboardHintVisible = props.controls.forceKeyboardHintVisible, slots = props.controls.slots, tools = tools, - unlocked = props.controls.unlocked, opened = props.controls.opened, }) end, From f2f146738c1d085f5477dc0566bc7b3e44f51ed7 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 9 Mar 2026 01:37:08 -0700 Subject: [PATCH 049/186] Add basic API Signed-off-by: Ryan Luu --- src/Api/closeInventory.luau | 0 src/Api/getInventoryVisible.luau | 0 src/Api/getTopbarIcon.luau | 0 src/Api/openInventory.luau | 0 src/Api/setEnabled.luau | 0 src/Api/setInventoryVisible.luau | 0 .../BackpackItemAdded.model.json | 3 ++ .../BackpackItemEquipped.model.json | 3 ++ .../BackpackItemRemoved.model.json | 3 ++ .../BackpackItemUnequipped.model.json | 3 ++ src/BindableEvents/InventoryClosed.model.json | 3 ++ src/BindableEvents/InventoryOpened.model.json | 3 ++ .../InventoryToggled.model.json | 3 ++ src/init.luau | 40 ++++++++----------- 14 files changed, 38 insertions(+), 23 deletions(-) create mode 100644 src/Api/closeInventory.luau create mode 100644 src/Api/getInventoryVisible.luau create mode 100644 src/Api/getTopbarIcon.luau create mode 100644 src/Api/openInventory.luau create mode 100644 src/Api/setEnabled.luau create mode 100644 src/Api/setInventoryVisible.luau create mode 100644 src/BindableEvents/BackpackItemAdded.model.json create mode 100644 src/BindableEvents/BackpackItemEquipped.model.json create mode 100644 src/BindableEvents/BackpackItemRemoved.model.json create mode 100644 src/BindableEvents/BackpackItemUnequipped.model.json create mode 100644 src/BindableEvents/InventoryClosed.model.json create mode 100644 src/BindableEvents/InventoryOpened.model.json create mode 100644 src/BindableEvents/InventoryToggled.model.json diff --git a/src/Api/closeInventory.luau b/src/Api/closeInventory.luau new file mode 100644 index 00000000..e69de29b diff --git a/src/Api/getInventoryVisible.luau b/src/Api/getInventoryVisible.luau new file mode 100644 index 00000000..e69de29b diff --git a/src/Api/getTopbarIcon.luau b/src/Api/getTopbarIcon.luau new file mode 100644 index 00000000..e69de29b diff --git a/src/Api/openInventory.luau b/src/Api/openInventory.luau new file mode 100644 index 00000000..e69de29b diff --git a/src/Api/setEnabled.luau b/src/Api/setEnabled.luau new file mode 100644 index 00000000..e69de29b diff --git a/src/Api/setInventoryVisible.luau b/src/Api/setInventoryVisible.luau new file mode 100644 index 00000000..e69de29b diff --git a/src/BindableEvents/BackpackItemAdded.model.json b/src/BindableEvents/BackpackItemAdded.model.json new file mode 100644 index 00000000..1399ec04 --- /dev/null +++ b/src/BindableEvents/BackpackItemAdded.model.json @@ -0,0 +1,3 @@ +{ + "ClassName": "BindableEvent" +} \ No newline at end of file diff --git a/src/BindableEvents/BackpackItemEquipped.model.json b/src/BindableEvents/BackpackItemEquipped.model.json new file mode 100644 index 00000000..1399ec04 --- /dev/null +++ b/src/BindableEvents/BackpackItemEquipped.model.json @@ -0,0 +1,3 @@ +{ + "ClassName": "BindableEvent" +} \ No newline at end of file diff --git a/src/BindableEvents/BackpackItemRemoved.model.json b/src/BindableEvents/BackpackItemRemoved.model.json new file mode 100644 index 00000000..1399ec04 --- /dev/null +++ b/src/BindableEvents/BackpackItemRemoved.model.json @@ -0,0 +1,3 @@ +{ + "ClassName": "BindableEvent" +} \ No newline at end of file diff --git a/src/BindableEvents/BackpackItemUnequipped.model.json b/src/BindableEvents/BackpackItemUnequipped.model.json new file mode 100644 index 00000000..1399ec04 --- /dev/null +++ b/src/BindableEvents/BackpackItemUnequipped.model.json @@ -0,0 +1,3 @@ +{ + "ClassName": "BindableEvent" +} \ No newline at end of file diff --git a/src/BindableEvents/InventoryClosed.model.json b/src/BindableEvents/InventoryClosed.model.json new file mode 100644 index 00000000..1399ec04 --- /dev/null +++ b/src/BindableEvents/InventoryClosed.model.json @@ -0,0 +1,3 @@ +{ + "ClassName": "BindableEvent" +} \ No newline at end of file diff --git a/src/BindableEvents/InventoryOpened.model.json b/src/BindableEvents/InventoryOpened.model.json new file mode 100644 index 00000000..1399ec04 --- /dev/null +++ b/src/BindableEvents/InventoryOpened.model.json @@ -0,0 +1,3 @@ +{ + "ClassName": "BindableEvent" +} \ No newline at end of file diff --git a/src/BindableEvents/InventoryToggled.model.json b/src/BindableEvents/InventoryToggled.model.json new file mode 100644 index 00000000..1399ec04 --- /dev/null +++ b/src/BindableEvents/InventoryToggled.model.json @@ -0,0 +1,3 @@ +{ + "ClassName": "BindableEvent" +} \ No newline at end of file diff --git a/src/init.luau b/src/init.luau index e857918b..dcd7c564 100644 --- a/src/init.luau +++ b/src/init.luau @@ -1,27 +1,21 @@ --!strict -local Players = game:GetService("Players") +local bindableEvents = script.BindableEvents -local React = require(script.Parent.react) -local ReactRoblox = require(script.Parent["react-roblox"]) +return { + -- Functions + setEnabled = require(script.Api.setEnabled), + getTopbarIcon = require(script.Api.getTopbarIcon), + openInventory = require(script.Api.openInventory), + closeInventory = require(script.Api.closeInventory), + setInventoryVisible = require(script.Api.setInventoryVisible), -local Backpack = require(script.Components.Backpack) - -local player = Players.LocalPlayer :: Player -local playerGui = player.PlayerGui - -local handle = Instance.new("ScreenGui") -handle.Name = "SatchelGui" -handle.Parent = playerGui - -local root = ReactRoblox.createRoot(handle) -root:render(React.createElement(React.Fragment, nil, { - StyleLink = React.createElement("StyleLink", { - StyleSheet = script.Design.SatchelStyleSheet, - }), - Backpack = React.createElement(Backpack, { - opened = true, - }), -})) - -return {} + -- Events + backpackItemAdded = bindableEvents.BackpackItemAdded.Event, + backpackItemRemoved = bindableEvents.BackpackItemRemoved.Event, + backpackItemEquipped = bindableEvents.BackpackItemEquipped.Event, + backpackItemUnequipped = bindableEvents.BackpackItemUnequipped.Event, + inventoryOpened = bindableEvents.InventoryOpened.Event, + inventoryClosed = bindableEvents.InventoryClosed.Event, + inventoryToggled = bindableEvents.InventoryToggled.Event, +} From 8bd89f9a919c3871e8534e1a4ac90f2e26975feb Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 9 Mar 2026 01:47:50 -0700 Subject: [PATCH 050/186] Simplify API Signed-off-by: Ryan Luu --- src/Api/{getInventoryVisible.luau => isInventoryOpen.luau} | 0 src/Api/setInventoryVisible.luau | 0 src/BindableEvents/InventoryToggled.model.json | 3 --- src/init.luau | 3 +-- 4 files changed, 1 insertion(+), 5 deletions(-) rename src/Api/{getInventoryVisible.luau => isInventoryOpen.luau} (100%) delete mode 100644 src/Api/setInventoryVisible.luau delete mode 100644 src/BindableEvents/InventoryToggled.model.json diff --git a/src/Api/getInventoryVisible.luau b/src/Api/isInventoryOpen.luau similarity index 100% rename from src/Api/getInventoryVisible.luau rename to src/Api/isInventoryOpen.luau diff --git a/src/Api/setInventoryVisible.luau b/src/Api/setInventoryVisible.luau deleted file mode 100644 index e69de29b..00000000 diff --git a/src/BindableEvents/InventoryToggled.model.json b/src/BindableEvents/InventoryToggled.model.json deleted file mode 100644 index 1399ec04..00000000 --- a/src/BindableEvents/InventoryToggled.model.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "ClassName": "BindableEvent" -} \ No newline at end of file diff --git a/src/init.luau b/src/init.luau index dcd7c564..3dc68d84 100644 --- a/src/init.luau +++ b/src/init.luau @@ -8,7 +8,7 @@ return { getTopbarIcon = require(script.Api.getTopbarIcon), openInventory = require(script.Api.openInventory), closeInventory = require(script.Api.closeInventory), - setInventoryVisible = require(script.Api.setInventoryVisible), + isInventoryOpen = require(script.Api.isInventoryOpen), -- Events backpackItemAdded = bindableEvents.BackpackItemAdded.Event, @@ -17,5 +17,4 @@ return { backpackItemUnequipped = bindableEvents.BackpackItemUnequipped.Event, inventoryOpened = bindableEvents.InventoryOpened.Event, inventoryClosed = bindableEvents.InventoryClosed.Event, - inventoryToggled = bindableEvents.InventoryToggled.Event, } From 08ee32c5c233609deea4d64b64087f808132ee23 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 9 Mar 2026 02:12:49 -0700 Subject: [PATCH 051/186] Add placeholders Signed-off-by: Ryan Luu --- src/Api/closeInventory.luau | 8 ++++++++ src/Api/getTopbarIcon.luau | 11 +++++++++++ src/Api/isInventoryOpen.luau | 8 ++++++++ src/Api/openInventory.luau | 8 ++++++++ src/Api/setEnabled.luau | 5 +++++ 5 files changed, 40 insertions(+) diff --git a/src/Api/closeInventory.luau b/src/Api/closeInventory.luau index e69de29b..139e8f1d 100644 --- a/src/Api/closeInventory.luau +++ b/src/Api/closeInventory.luau @@ -0,0 +1,8 @@ +local RunService = game:GetService("RunService") + +local function closeInventory() + assert(RunService:IsClient(), "closeInventory can only be called on the client") + print("Not implemented") +end + +return closeInventory diff --git a/src/Api/getTopbarIcon.luau b/src/Api/getTopbarIcon.luau index e69de29b..dc2a9e34 100644 --- a/src/Api/getTopbarIcon.luau +++ b/src/Api/getTopbarIcon.luau @@ -0,0 +1,11 @@ +local TopbarPlus = require(script.Parent.Parent.Parent.topbarplus) + +local RunService = game:GetService("RunService") + +local function getTopbarIcon(): TopbarPlus.Icon + assert(RunService:IsClient(), "getTopbarIcon can only be called on the client") + print("Not implemented") + return nil +end + +return getTopbarIcon diff --git a/src/Api/isInventoryOpen.luau b/src/Api/isInventoryOpen.luau index e69de29b..348c76a8 100644 --- a/src/Api/isInventoryOpen.luau +++ b/src/Api/isInventoryOpen.luau @@ -0,0 +1,8 @@ +local RunService = game:GetService("RunService") + +local function isInventoryOpen(): boolean + assert(RunService:IsClient(), "isInventoryOpen can only be called on the client") + return nil -- Not implemented +end + +return isInventoryOpen diff --git a/src/Api/openInventory.luau b/src/Api/openInventory.luau index e69de29b..777c30db 100644 --- a/src/Api/openInventory.luau +++ b/src/Api/openInventory.luau @@ -0,0 +1,8 @@ +local RunService = game:GetService("RunService") + +local function openInventory() + assert(RunService:IsClient(), "openInventory can only be called on the client") + print("Not implemented") +end + +return openInventory diff --git a/src/Api/setEnabled.luau b/src/Api/setEnabled.luau index e69de29b..f06700ce 100644 --- a/src/Api/setEnabled.luau +++ b/src/Api/setEnabled.luau @@ -0,0 +1,5 @@ +local function setEnabled(isEnabled: boolean) + print("Not implemented") +end + +return setEnabled From 293ca0cf93ea6d8aaafd7c46f913fbd452703f5d Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 9 Mar 2026 02:17:20 -0700 Subject: [PATCH 052/186] Use strict Signed-off-by: Ryan Luu --- src/Api/closeInventory.luau | 2 ++ src/Api/getTopbarIcon.luau | 4 +++- src/Api/isInventoryOpen.luau | 2 ++ src/Api/openInventory.luau | 2 ++ src/Api/setEnabled.luau | 2 ++ 5 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Api/closeInventory.luau b/src/Api/closeInventory.luau index 139e8f1d..8bc9855a 100644 --- a/src/Api/closeInventory.luau +++ b/src/Api/closeInventory.luau @@ -1,3 +1,5 @@ +--!strict + local RunService = game:GetService("RunService") local function closeInventory() diff --git a/src/Api/getTopbarIcon.luau b/src/Api/getTopbarIcon.luau index dc2a9e34..56ff2e3d 100644 --- a/src/Api/getTopbarIcon.luau +++ b/src/Api/getTopbarIcon.luau @@ -1,7 +1,9 @@ -local TopbarPlus = require(script.Parent.Parent.Parent.topbarplus) +--!strict local RunService = game:GetService("RunService") +local TopbarPlus = require(script.Parent.Parent.Parent.topbarplus) + local function getTopbarIcon(): TopbarPlus.Icon assert(RunService:IsClient(), "getTopbarIcon can only be called on the client") print("Not implemented") diff --git a/src/Api/isInventoryOpen.luau b/src/Api/isInventoryOpen.luau index 348c76a8..b18b9cb8 100644 --- a/src/Api/isInventoryOpen.luau +++ b/src/Api/isInventoryOpen.luau @@ -1,3 +1,5 @@ +--!strict + local RunService = game:GetService("RunService") local function isInventoryOpen(): boolean diff --git a/src/Api/openInventory.luau b/src/Api/openInventory.luau index 777c30db..8ab5e386 100644 --- a/src/Api/openInventory.luau +++ b/src/Api/openInventory.luau @@ -1,3 +1,5 @@ +--!strict + local RunService = game:GetService("RunService") local function openInventory() diff --git a/src/Api/setEnabled.luau b/src/Api/setEnabled.luau index f06700ce..0142f385 100644 --- a/src/Api/setEnabled.luau +++ b/src/Api/setEnabled.luau @@ -1,3 +1,5 @@ +--!strict + local function setEnabled(isEnabled: boolean) print("Not implemented") end From 1623e52fc7f19efa3e11c1b9e78a7a1bbe1c337d Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 9 Mar 2026 02:19:41 -0700 Subject: [PATCH 053/186] Use require by string Signed-off-by: Ryan Luu --- src/Api/getTopbarIcon.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Api/getTopbarIcon.luau b/src/Api/getTopbarIcon.luau index 56ff2e3d..d4dedf51 100644 --- a/src/Api/getTopbarIcon.luau +++ b/src/Api/getTopbarIcon.luau @@ -2,7 +2,7 @@ local RunService = game:GetService("RunService") -local TopbarPlus = require(script.Parent.Parent.Parent.topbarplus) +local TopbarPlus = require("../../topbarplus") local function getTopbarIcon(): TopbarPlus.Icon assert(RunService:IsClient(), "getTopbarIcon can only be called on the client") From 36d768e1c7aa5adfd1d7ba7bd33450f4fde50407 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 9 Mar 2026 02:28:04 -0700 Subject: [PATCH 054/186] Separate stories Signed-off-by: Ryan Luu --- src/{Components => Stories}/Backpack.story.luau | 2 +- src/{Components => Stories}/Hotbar.story.luau | 2 +- src/{Components => Stories}/HotbarHint.story.luau | 2 +- src/{Components => Stories}/Inventory.story.luau | 2 +- src/{Components => Stories}/Satchel.storybook.luau | 0 src/{Components => Stories}/Searchbar.story.luau | 2 +- src/{Components => Stories}/Slot.story.luau | 2 +- src/{Components => Stories}/Tooltip.story.luau | 2 +- 8 files changed, 7 insertions(+), 7 deletions(-) rename src/{Components => Stories}/Backpack.story.luau (93%) rename src/{Components => Stories}/Hotbar.story.luau (94%) rename src/{Components => Stories}/HotbarHint.story.luau (86%) rename src/{Components => Stories}/Inventory.story.luau (79%) rename src/{Components => Stories}/Satchel.storybook.luau (100%) rename src/{Components => Stories}/Searchbar.story.luau (77%) rename src/{Components => Stories}/Slot.story.luau (93%) rename src/{Components => Stories}/Tooltip.story.luau (85%) diff --git a/src/Components/Backpack.story.luau b/src/Stories/Backpack.story.luau similarity index 93% rename from src/Components/Backpack.story.luau rename to src/Stories/Backpack.story.luau index ca9c1b95..cea21d19 100644 --- a/src/Components/Backpack.story.luau +++ b/src/Stories/Backpack.story.luau @@ -2,7 +2,7 @@ local React = require(script.Parent.Parent.Parent.react) -local Backpack = require(script.Parent.Backpack) +local Backpack = require(script.Parent.Parent.Components.Backpack) local controls = { forceGamepadHintVisible = true, diff --git a/src/Components/Hotbar.story.luau b/src/Stories/Hotbar.story.luau similarity index 94% rename from src/Components/Hotbar.story.luau rename to src/Stories/Hotbar.story.luau index b5f37c2e..fb520dae 100644 --- a/src/Components/Hotbar.story.luau +++ b/src/Stories/Hotbar.story.luau @@ -2,7 +2,7 @@ local React = require(script.Parent.Parent.Parent.react) -local Hotbar = require(script.Parent.Hotbar) +local Hotbar = require(script.Parent.Parent.Components.Hotbar) local controls = { forceGamepadHintVisible = true, diff --git a/src/Components/HotbarHint.story.luau b/src/Stories/HotbarHint.story.luau similarity index 86% rename from src/Components/HotbarHint.story.luau rename to src/Stories/HotbarHint.story.luau index dd6fb9fa..b81a37c4 100644 --- a/src/Components/HotbarHint.story.luau +++ b/src/Stories/HotbarHint.story.luau @@ -2,7 +2,7 @@ local React = require(script.Parent.Parent.Parent.react) -local HotbarHint = require(script.Parent.HotbarHint) +local HotbarHint = require(script.Parent.Parent.Components.HotbarHint) local controls = { forceVisible = true, diff --git a/src/Components/Inventory.story.luau b/src/Stories/Inventory.story.luau similarity index 79% rename from src/Components/Inventory.story.luau rename to src/Stories/Inventory.story.luau index 26e745bf..a3a8ce01 100644 --- a/src/Components/Inventory.story.luau +++ b/src/Stories/Inventory.story.luau @@ -2,7 +2,7 @@ local React = require(script.Parent.Parent.Parent.react) -local Inventory = require(script.Parent.Inventory) +local Inventory = require(script.Parent.Parent.Components.Inventory) return { summary = "Toggleable inventory for displaying items not in the hotbar", diff --git a/src/Components/Satchel.storybook.luau b/src/Stories/Satchel.storybook.luau similarity index 100% rename from src/Components/Satchel.storybook.luau rename to src/Stories/Satchel.storybook.luau diff --git a/src/Components/Searchbar.story.luau b/src/Stories/Searchbar.story.luau similarity index 77% rename from src/Components/Searchbar.story.luau rename to src/Stories/Searchbar.story.luau index f2ba6f87..c6d8c327 100644 --- a/src/Components/Searchbar.story.luau +++ b/src/Stories/Searchbar.story.luau @@ -2,7 +2,7 @@ local React = require(script.Parent.Parent.Parent.react) -local Searchbar = require(script.Parent.Searchbar) +local Searchbar = require(script.Parent.Parent.Components.Searchbar) return { summary = "Search for items in the inventory", diff --git a/src/Components/Slot.story.luau b/src/Stories/Slot.story.luau similarity index 93% rename from src/Components/Slot.story.luau rename to src/Stories/Slot.story.luau index db7cb1b0..f4cd625f 100644 --- a/src/Components/Slot.story.luau +++ b/src/Stories/Slot.story.luau @@ -2,7 +2,7 @@ local React = require(script.Parent.Parent.Parent.react) -local Slot = require(script.Parent.Slot) +local Slot = require(script.Parent.Parent.Components.Slot) local controls = { toolName = "Sword", diff --git a/src/Components/Tooltip.story.luau b/src/Stories/Tooltip.story.luau similarity index 85% rename from src/Components/Tooltip.story.luau rename to src/Stories/Tooltip.story.luau index 60d857d3..6ec7aac5 100644 --- a/src/Components/Tooltip.story.luau +++ b/src/Stories/Tooltip.story.luau @@ -2,7 +2,7 @@ local React = require(script.Parent.Parent.Parent.react) -local Tooltip = require(script.Parent.Tooltip) +local Tooltip = require(script.Parent.Parent.Components.Tooltip) local controls = { text = "I'm a tooltip!", From 853c687efb4a129523b2b172235955ddf65bd8bc Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 9 Mar 2026 02:29:45 -0700 Subject: [PATCH 055/186] Don't return nil Signed-off-by: Ryan Luu --- src/Components/Tooltip.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Tooltip.luau b/src/Components/Tooltip.luau index 68857db9..c6a2cec1 100644 --- a/src/Components/Tooltip.luau +++ b/src/Components/Tooltip.luau @@ -9,7 +9,7 @@ export type Props = { local function Tooltip(props: Props) -- Hide tooltip if there is no text if not props.text or props.text == "" then - return nil + return end return React.createElement("TextLabel", { From 797cdb62360e3c7dac0ce51206313c1b9318ed25 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 9 Mar 2026 23:41:09 -0700 Subject: [PATCH 056/186] Fix misnamed prop Signed-off-by: Ryan Luu --- src/Components/Hotbar.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Hotbar.luau b/src/Components/Hotbar.luau index 4a690db0..30dd45fd 100644 --- a/src/Components/Hotbar.luau +++ b/src/Components/Hotbar.luau @@ -27,7 +27,7 @@ local function Hotbar(props: Props) children[slotNumber] = React.createElement(Slot, { order = slotNumber, tool = tool, - forceNumberVisible = props.forceKeyboardHintVisible, + forceHintVisible = props.forceKeyboardHintVisible, unlocked = slotUnlocked, }) end From 0f683290de5dcdd1b4920cc04d8d153e9af714c8 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 9 Mar 2026 23:47:05 -0700 Subject: [PATCH 057/186] Don't use hardcoded hints Signed-off-by: Ryan Luu --- src/Components/Hotbar.luau | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Components/Hotbar.luau b/src/Components/Hotbar.luau index 30dd45fd..9bff196f 100644 --- a/src/Components/Hotbar.luau +++ b/src/Components/Hotbar.luau @@ -5,6 +5,10 @@ local React = require(script.Parent.Parent.Parent.react) local HotbarHint = require(script.Parent.HotbarHint) local Slot = require(script.Parent.Slot) +local HotbarBindings = script.Parent.Parent.Bindings.HotbarContext +local SlotLeftGamepadKeyCode = HotbarBindings.SlotLeftAction.GamepadBinding.KeyCode +local SlotRightGamepadKeyCode = HotbarBindings.SlotRightAction.GamepadBinding.KeyCode + export type Props = { forceGamepadHintVisible: boolean?, forceKeyboardHintVisible: boolean?, @@ -36,12 +40,12 @@ local function Hotbar(props: Props) if next(children) then -- Create default hints for equipping between hotbar slots children.SlotLeftHint = React.createElement(HotbarHint, { - keyCode = Enum.KeyCode.ButtonL1, + keyCode = SlotLeftGamepadKeyCode, forceVisible = props.forceGamepadHintVisible, order = -1, }) children.SlotRightHint = React.createElement(HotbarHint, { - keyCode = Enum.KeyCode.ButtonR1, + keyCode = SlotRightGamepadKeyCode, forceVisible = props.forceGamepadHintVisible, order = 100, }) From 796b91ad62b1125486ba3cf61ee76136acb9d5ae Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 9 Mar 2026 23:58:33 -0700 Subject: [PATCH 058/186] Remove bindings for slot numbers since they shouldn't be rebinded Signed-off-by: Ryan Luu --- src/Bindings/HotbarContext.model.json | 260 +++++++++++++------------- 1 file changed, 130 insertions(+), 130 deletions(-) diff --git a/src/Bindings/HotbarContext.model.json b/src/Bindings/HotbarContext.model.json index 35ef6372..561d9f10 100644 --- a/src/Bindings/HotbarContext.model.json +++ b/src/Bindings/HotbarContext.model.json @@ -30,136 +30,136 @@ } ] }, - { - "Name": "SlotOneAction", - "ClassName": "InputAction", - "Children": [ - { - "Name": "KeyBinding", - "ClassName": "InputBinding", - "Properties": { - "KeyCode": "One" - } - } - ] - }, - { - "Name": "SlotTwoAction", - "ClassName": "InputAction", - "Children": [ - { - "Name": "KeyBinding", - "ClassName": "InputBinding", - "Properties": { - "KeyCode": "Two" - } - } - ] - }, - { - "Name": "SlotThreeAction", - "ClassName": "InputAction", - "Children": [ - { - "Name": "KeyBinding", - "ClassName": "InputBinding", - "Properties": { - "KeyCode": "Three" - } - } - ] - }, - { - "Name": "SlotFourAction", - "ClassName": "InputAction", - "Children": [ - { - "Name": "KeyBinding", - "ClassName": "InputBinding", - "Properties": { - "KeyCode": "Four" - } - } - ] - }, - { - "Name": "SlotFiveAction", - "ClassName": "InputAction", - "Children": [ - { - "Name": "KeyBinding", - "ClassName": "InputBinding", - "Properties": { - "KeyCode": "Five" - } - } - ] - }, - { - "Name": "SlotSixAction", - "ClassName": "InputAction", - "Children": [ - { - "Name": "KeyBinding", - "ClassName": "InputBinding", - "Properties": { - "KeyCode": "Six" - } - } - ] - }, - { - "Name": "SlotSevenAction", - "ClassName": "InputAction", - "Children": [ - { - "Name": "KeyBinding", - "ClassName": "InputBinding", - "Properties": { - "KeyCode": "Seven" - } - } - ] - }, - { - "Name": "SlotEightAction", - "ClassName": "InputAction", - "Children": [ - { - "Name": "KeyBinding", - "ClassName": "InputBinding", - "Properties": { - "KeyCode": "Eight" - } - } - ] - }, - { - "Name": "SlotNineAction", - "ClassName": "InputAction", - "Children": [ - { - "Name": "KeyBinding", - "ClassName": "InputBinding", - "Properties": { - "KeyCode": "Nine" - } - } - ] - }, - { - "Name": "SlotZeroAction", - "ClassName": "InputAction", - "Children": [ - { - "Name": "KeyBinding", - "ClassName": "InputBinding", - "Properties": { - "KeyCode": "Zero" - } - } - ] - }, + // { + // "Name": "SlotOneAction", + // "ClassName": "InputAction", + // "Children": [ + // { + // "Name": "KeyBinding", + // "ClassName": "InputBinding", + // "Properties": { + // "KeyCode": "One" + // } + // } + // ] + // }, + // { + // "Name": "SlotTwoAction", + // "ClassName": "InputAction", + // "Children": [ + // { + // "Name": "KeyBinding", + // "ClassName": "InputBinding", + // "Properties": { + // "KeyCode": "Two" + // } + // } + // ] + // }, + // { + // "Name": "SlotThreeAction", + // "ClassName": "InputAction", + // "Children": [ + // { + // "Name": "KeyBinding", + // "ClassName": "InputBinding", + // "Properties": { + // "KeyCode": "Three" + // } + // } + // ] + // }, + // { + // "Name": "SlotFourAction", + // "ClassName": "InputAction", + // "Children": [ + // { + // "Name": "KeyBinding", + // "ClassName": "InputBinding", + // "Properties": { + // "KeyCode": "Four" + // } + // } + // ] + // }, + // { + // "Name": "SlotFiveAction", + // "ClassName": "InputAction", + // "Children": [ + // { + // "Name": "KeyBinding", + // "ClassName": "InputBinding", + // "Properties": { + // "KeyCode": "Five" + // } + // } + // ] + // }, + // { + // "Name": "SlotSixAction", + // "ClassName": "InputAction", + // "Children": [ + // { + // "Name": "KeyBinding", + // "ClassName": "InputBinding", + // "Properties": { + // "KeyCode": "Six" + // } + // } + // ] + // }, + // { + // "Name": "SlotSevenAction", + // "ClassName": "InputAction", + // "Children": [ + // { + // "Name": "KeyBinding", + // "ClassName": "InputBinding", + // "Properties": { + // "KeyCode": "Seven" + // } + // } + // ] + // }, + // { + // "Name": "SlotEightAction", + // "ClassName": "InputAction", + // "Children": [ + // { + // "Name": "KeyBinding", + // "ClassName": "InputBinding", + // "Properties": { + // "KeyCode": "Eight" + // } + // } + // ] + // }, + // { + // "Name": "SlotNineAction", + // "ClassName": "InputAction", + // "Children": [ + // { + // "Name": "KeyBinding", + // "ClassName": "InputBinding", + // "Properties": { + // "KeyCode": "Nine" + // } + // } + // ] + // }, + // { + // "Name": "SlotZeroAction", + // "ClassName": "InputAction", + // "Children": [ + // { + // "Name": "KeyBinding", + // "ClassName": "InputBinding", + // "Properties": { + // "KeyCode": "Zero" + // } + // } + // ] + // }, { "Name": "ToggleInventoryAction", "ClassName": "InputAction", From 57c7e1af75973e0499e3d484921bd10bdddcd5f3 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Tue, 10 Mar 2026 01:12:22 -0700 Subject: [PATCH 059/186] Remove on activated prop Signed-off-by: Ryan Luu --- src/Components/Slot.luau | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Components/Slot.luau b/src/Components/Slot.luau index e784d096..1309e0a4 100644 --- a/src/Components/Slot.luau +++ b/src/Components/Slot.luau @@ -12,7 +12,6 @@ export type Props = { unlocked: boolean?, forceHintVisible: boolean?, order: number?, - onActivated: (() -> ())?, } local function Slot(props: Props) @@ -75,7 +74,9 @@ local function Slot(props: Props) Text = slotText, LayoutOrder = props.order, [React.Tag] = tags, - [React.Event.Activated] = props.onActivated, + [React.Event.Activated] = function() + print("Slot activated")) + end, }, { NumberHint = React.createElement("TextLabel", { Text = slotNumber, From f4063a7541f2dfb6131132f78a7ead2cc3a583fa Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 12 Mar 2026 01:40:39 -0700 Subject: [PATCH 060/186] Remove controls for previewing hotbar hint Signed-off-by: Ryan Luu --- src/Stories/HotbarHint.story.luau | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/Stories/HotbarHint.story.luau b/src/Stories/HotbarHint.story.luau index b81a37c4..dbb91033 100644 --- a/src/Stories/HotbarHint.story.luau +++ b/src/Stories/HotbarHint.story.luau @@ -4,22 +4,13 @@ local React = require(script.Parent.Parent.Parent.react) local HotbarHint = require(script.Parent.Parent.Components.HotbarHint) -local controls = { - forceVisible = true, -} - -type Props = { - controls: typeof(controls), -} - return { name = "Hotbar Hint", summary = "Hint shown in the hotbar to show how to equip slots", - controls = controls, - story = function(props: Props) + story = function() return React.createElement(HotbarHint, { keyCode = Enum.KeyCode.ButtonX, - forceVisible = props.controls.forceVisible, + forceVisible = true, }) end, } From 5726bc1026424f2c2ce19bb18c10584f17b07e08 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 12 Mar 2026 01:41:51 -0700 Subject: [PATCH 061/186] Fix extra '(' Signed-off-by: Ryan Luu --- src/Components/Slot.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Slot.luau b/src/Components/Slot.luau index 1309e0a4..ce976afa 100644 --- a/src/Components/Slot.luau +++ b/src/Components/Slot.luau @@ -75,7 +75,7 @@ local function Slot(props: Props) LayoutOrder = props.order, [React.Tag] = tags, [React.Event.Activated] = function() - print("Slot activated")) + print("Slot activated") end, }, { NumberHint = React.createElement("TextLabel", { From 09555ef511e29e8620e0fffdd74fa1aeeda96a10 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 12 Mar 2026 01:48:14 -0700 Subject: [PATCH 062/186] Cleanup story controls Signed-off-by: Ryan Luu --- src/Stories/Backpack.story.luau | 10 ++++------ src/Stories/Hotbar.story.luau | 6 ++---- src/Stories/Slot.story.luau | 6 ++---- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/Stories/Backpack.story.luau b/src/Stories/Backpack.story.luau index cea21d19..4a93b80e 100644 --- a/src/Stories/Backpack.story.luau +++ b/src/Stories/Backpack.story.luau @@ -5,12 +5,11 @@ local React = require(script.Parent.Parent.Parent.react) local Backpack = require(script.Parent.Parent.Components.Backpack) local controls = { - forceGamepadHintVisible = true, - forceKeyboardHintVisible = true, + hintVisible = true, slots = 10, toolName = "Sword", toolImage = "rbxasset://Textures/Sword128.png", - tooltipText = "A classic sword", + toolTooltip = "A classic sword", toolSlot = 1, opened = false, } @@ -26,11 +25,10 @@ return { local Tool = Instance.new("Tool") Tool.Name = props.controls.toolName Tool.TextureId = props.controls.toolImage - Tool.ToolTip = props.controls.tooltipText + Tool.ToolTip = props.controls.toolTooltip return React.createElement(Backpack, { - forceGamepadHintVisible = props.controls.forceGamepadHintVisible, - forceKeyboardHintVisible = props.controls.forceKeyboardHintVisible, + forceGamepadHintVisible = props.controls.hintVisible, slots = props.controls.slots, tools = { [props.controls.toolSlot] = Tool }, opened = props.controls.opened, diff --git a/src/Stories/Hotbar.story.luau b/src/Stories/Hotbar.story.luau index fb520dae..32a13e99 100644 --- a/src/Stories/Hotbar.story.luau +++ b/src/Stories/Hotbar.story.luau @@ -5,8 +5,7 @@ local React = require(script.Parent.Parent.Parent.react) local Hotbar = require(script.Parent.Parent.Components.Hotbar) local controls = { - forceGamepadHintVisible = true, - forceKeyboardHintVisible = true, + hintVisible = true, slots = 10, toolName = "Sword", toolImage = "rbxasset://Textures/Sword128.png", @@ -32,8 +31,7 @@ return { tools[props.controls.toolSlot] = tool return React.createElement(Hotbar, { - forceGamepadHintVisible = props.controls.forceGamepadHintVisible, - forceKeyboardHintVisible = props.controls.forceKeyboardHintVisible, + forceGamepadHintVisible = props.controls.hintVisible, slots = props.controls.slots, tools = tools, opened = props.controls.opened, diff --git a/src/Stories/Slot.story.luau b/src/Stories/Slot.story.luau index f4cd625f..b92136dd 100644 --- a/src/Stories/Slot.story.luau +++ b/src/Stories/Slot.story.luau @@ -7,11 +7,10 @@ local Slot = require(script.Parent.Parent.Components.Slot) local controls = { toolName = "Sword", toolImage = "rbxasset://Textures/Sword128.png", - tooltipText = "A classic sword", + toolTooltip = "A classic sword", equipped = false, unlocked = false, order = 1, - forceHintVisible = true, } type Props = { @@ -25,14 +24,13 @@ return { local Tool = Instance.new("Tool") Tool.Name = props.controls.toolName Tool.TextureId = props.controls.toolImage - Tool.ToolTip = props.controls.tooltipText + Tool.ToolTip = props.controls.toolTooltip return React.createElement(Slot, { tool = Tool, equipped = props.controls.equipped, unlocked = props.controls.unlocked, order = props.controls.order, - forceHintVisible = props.controls.forceHintVisible, }) end, } From 2b1989f8f9d42c77100978dea637cfa98a1cc229 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 12 Mar 2026 02:04:06 -0700 Subject: [PATCH 063/186] Use dynamic sizing for hotbar Signed-off-by: Ryan Luu --- src/Design.rbxmx | 1287 +++++++++++++++++++++++----------------------- 1 file changed, 636 insertions(+), 651 deletions(-) diff --git a/src/Design.rbxmx b/src/Design.rbxmx index 0c198d7f..1f9a9d64 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,7 +11,7 @@ -1 - + - - - - 0 - false - LegacyTheme - -1 - - - - - 0 - RBXA8178370153F478B9B12E6598F085157 - - 0 - false - Derive from BaseTokens - -1 - - - - - - - AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= - 0 - false - DefaultTheme - -1 - - - - - 0 - RBXA8178370153F478B9B12E6598F085157 - - 0 - false - Derive from BaseTokens - -1 - - - - - + -1 - + 0 - RBX68E8F4AB849D40F6BF3DC148319A05B7 + RBX30E432006E76471DA6F53F0F3AF357A3 0 false @@ -138,474 +81,258 @@ VGV4dFNpemU=]]> - + - + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= 0 false - SatchelStyleSheet + DefaultTheme -1 - + 0 - RBX5904AEDE67814AE7A33FBBBB90C2112D + RBXCD49C302BBB6416DAC42DDF502AF51D4 0 false - Derive from DefaultTheme + Derive from BaseTokens -1 - + + + + + 0 + false + SatchelStyleSheet + -1 + + + - 8 + 12 AAAAAA== - TextButton + Frame 0 false - TextButton + Frame -1 - + 2 - + - .Slot + .Hint 0 false - .Slot + .Hint -1 - + - 9 - AAAAAA== + 3 + - :Press + >TextLabel 0 false - :Press + >TextLabel -1 - - - 2 - AQAAAAcAAABWaXNpYmxlAwE= - - >.Tooltip - - 0 - false - >.Tooltip - -1 - - - - + - 10 - AAAAAA== + 4 + - .Equipped + >ImageLabel 0 false - .Equipped + >ImageLabel -1 - + 1 - - - ::UIStroke - - 0 - false - ::UIStroke - -1 - - - - - - - 11 - - - .Unlocked - - 0 - false - .Unlocked - -1 - - - - - 9 AAAAAA== - :Press + ::UIAspectRatioConstraint 0 false - :Press + ::UIAspectRatioConstraint -1 - - - 1 - - - ::UIStroke - - 0 - false - ::UIStroke - -1 - - - - + + + + + 10 + AAAAAA== + + TextLabel + + 0 + false + TextLabel + -1 + + + + + 9 + + + .Tooltip + + 0 + false + .Tooltip + -1 + + + - 4 - AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= + 2 + - >TextLabel + ::UIPadding 0 false - >TextLabel + ::UIPadding -1 - - - 1 - - - .SlotNumber - - 0 - false - .SlotNumber - -1 - - - - - - 9 - AQAAAAcAAABWaXNpYmxlAwA= - - .Tooltip - - 0 - false - .Tooltip - -1 - - - - + - 8 - AAAAAA== + 1 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz - :Hover + ::UICorner 0 false - :Hover + ::UICorner -1 - - - 1 - AQAAAAcAAABWaXNpYmxlAwE= - - >.Tooltip - - 0 - false - >.Tooltip - -1 - - - - - - - 5 - - - ::UIPadding - - 0 - false - ::UIPadding - -1 - - - - - - 1 - AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - - - 6 - - - ::UITextSizeConstraint - - 0 - false - ::UITextSizeConstraint - -1 - - - - - - 7 - - - >ImageLabel - - 0 - false - >ImageLabel - -1 - - - - - 1 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - + - 12 + 11 AAAAAA== - Frame + ScrollingFrame 0 false - Frame + ScrollingFrame -1 - - - 2 - - - .Hint - - 0 - false - .Hint - -1 - - - - - 3 - - - >TextLabel - - 0 - false - >TextLabel - -1 - - - - - - 4 - - - >ImageLabel - - 0 - false - >ImageLabel - -1 - - - - - 1 - AAAAAA== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - - - + 3 - + - .Container,.Searchbar + .Surface,.Inventory 0 false - .Container,.Searchbar + .Surface,.Inventory -1 - + - 2 - + 1 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz - ::UIPadding + ::UICorner 0 false - ::UIPadding + ::UICorner -1 - + 2 - - - ::UIStroke - - 0 - false - ::UIStroke - -1 - - - - - - 1 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= + - ::UICorner + ::UIPadding 0 false - ::UICorner + ::UIPadding -1 - + - 5 - + 8 + - .Hotbar + .Backpack 0 false - .Hotbar + .Backpack -1 - + 1 - + ::UIListLayout @@ -617,89 +344,445 @@ aWdubWVudBURAAAAVmVydGljYWxBbGlnbm1lbnQAAAAA]]> - + - 3 - + 6 + AAAAAA== - .Surface,.Inventory + ImageButton 0 false - .Surface,.Inventory + ImageButton + -1 + + + + + + 0 + RBX0A0BA56913F44041AC7AC7D58D86E66B + + 0 + false + Derive from DefaultTheme + -1 + + + + + + 7 + AQAAAAsAAABMYXlvdXRPcmRlcgYAAAAAAAAAAA== + + .Inventory + + 0 + false + .Inventory -1 - + 1 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz + AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA - ::UICorner + ::UIListLayout 0 false - ::UICorner + ::UIListLayout -1 - + - 2 - + 1 + - ::UIPadding + >ScrollingFrame 0 false - ::UIPadding + >ScrollingFrame -1 - - - - - 7 - AAAAAA== - - TextBox - + + + 2 + + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + + + + + + 5 + AAAAAA== + + ImageLabel + 0 false - TextBox + ImageLabel + -1 + + + + + 1 + + + .HintSlot + + 0 + false + .HintSlot + -1 + + + + + 1 + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== + + ::UIAspectRatioConstraint + + 0 + false + ::UIAspectRatioConstraint + -1 + + + + + + + + 6 + + + .Hints + + 0 + false + .Hints + -1 + + + + + 1 + + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + + + + + 8 + AAAAAA== + + TextButton + + 0 + false + TextButton -1 - + 2 - + - .Searchbar + .Slot 0 false - .Searchbar + .Slot -1 - + + + 10 + AAAAAA== + + .Equipped + + 0 + false + .Equipped + -1 + + + + + 1 + + + ::UIStroke + + 0 + false + ::UIStroke + -1 + + + + + + + 6 + + + ::UITextSizeConstraint + + 0 + false + ::UITextSizeConstraint + -1 + + + + + + 11 + + + .Unlocked + + 0 + false + .Unlocked + -1 + + + + + 9 + AAAAAA== + + :Press + + 0 + false + :Press + -1 + + + + + 1 + + + ::UIStroke + + 0 + false + ::UIStroke + -1 + + + + + + + + 7 + + + >ImageLabel + + 0 + false + >ImageLabel + -1 + + + + + 1 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== + + ::UICorner + + 0 + false + ::UICorner + -1 + + + + + + + 4 + AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= + + >TextLabel + + 0 + false + >TextLabel + -1 + + + + + 1 + + + .SlotNumber + + 0 + false + .SlotNumber + -1 + + + + + + 9 + AQAAAAcAAABWaXNpYmxlAwA= + + .Tooltip + + 0 + false + .Tooltip + -1 + + + + + + + 8 + AAAAAA== + + :Hover + + 0 + false + :Hover + -1 + + + + + 1 + AQAAAAcAAABWaXNpYmxlAwE= + + >.Tooltip + + 0 + false + >.Tooltip + -1 + + + + + + + 9 + AAAAAA== + + :Press + + 0 + false + :Press + -1 + + + + + 2 + AQAAAAcAAABWaXNpYmxlAwE= + + >.Tooltip + + 0 + false + >.Tooltip + -1 + + + + + 1 - + AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz + + ::UICorner + + 0 + false + ::UICorner + -1 + + + + + + 5 + ::UIPadding @@ -710,7 +793,40 @@ ZwoAAABQYWRkaW5nVG9wAg4AAAAkU2VhcmNoUGFkZGluZw==]]> - + + + + + 7 + AAAAAA== + + TextBox + + 0 + false + TextBox + -1 + + + + + 2 + + + .Searchbar + + 0 + false + .Searchbar + -1 + + + 3 -1 - + 1 AAAAAA== @@ -741,71 +857,44 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAAcAAABWaXNpYmxlAwA=]]> + + + 1 + + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + - - - 6 - AAAAAA== - - ImageButton - - 0 - false - ImageButton - -1 - - - - - - 11 - AAAAAA== - - ScrollingFrame - - 0 - false - ScrollingFrame - -1 - - - - + - 8 - + 5 + - .Backpack + .Hotbar 0 false - .Backpack + .Hotbar -1 - - - 2 - AQAAAA0AAABQYWRkaW5nQm90dG9tCQAAAAAFAAAA - - ::UIPadding - - 0 - false - ::UIPadding - -1 - - - - + 1 - + ::UIListLayout @@ -817,206 +906,102 @@ AABWZXJ0aWNhbEFsaWdubWVudBURAAAAVmVydGljYWxBbGlnbm1lbnQCAAAA]]> - + - 7 - AQAAAAsAAABMYXlvdXRPcmRlcgYAAAAAAAAAAA== + 3 + - .Inventory + .Container,.Searchbar 0 false - .Inventory + .Container,.Searchbar -1 - - - 1 - AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA - - ::UIListLayout - - 0 - false - ::UIListLayout - -1 - - - - + - 1 - + 2 + - >ScrollingFrame + ::UIStroke 0 false - >ScrollingFrame + ::UIStroke -1 - - - 2 - - - ::UIListLayout - - 0 - false - ::UIListLayout - -1 - - - - - - - 6 - - - .Hints - - 0 - false - .Hints - -1 - - - + 1 - + AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= - ::UIListLayout + ::UICorner 0 false - ::UIListLayout + ::UICorner -1 - - - - 10 - AAAAAA== - - TextLabel - - 0 - false - TextLabel - -1 - - - + - 9 - + 2 + - .Tooltip + ::UIPadding 0 false - .Tooltip + ::UIPadding -1 - - - 2 - - - ::UIPadding - - 0 - false - ::UIPadding - -1 - - - - - - 1 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - + + + + + 0 + false + LegacyTheme + -1 + + + - 5 - AAAAAA== - - ImageLabel + 0 + RBXCD49C302BBB6416DAC42DDF502AF51D4 0 false - ImageLabel + Derive from BaseTokens -1 - - - 1 - - - .HintSlot - - 0 - false - .HintSlot - -1 - - - - - 1 - AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - From 4fd9808f5778c8ccafb64013bfa5a69c8d4c6028 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 12 Mar 2026 02:26:34 -0700 Subject: [PATCH 064/186] Remove unused UI elements from preview Signed-off-by: Ryan Luu --- src/Design.rbxmx | 945 ++++++++++++++++++++--------------------------- 1 file changed, 402 insertions(+), 543 deletions(-) diff --git a/src/Design.rbxmx b/src/Design.rbxmx index 1f9a9d64..39fab8e3 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -112,227 +112,165 @@ VGV4dFNpemU=]]> -1 - + - 12 - AAAAAA== + 0 + - Frame + .Backpack 0 false - Frame + .Backpack -1 - + - 2 - + 0 + - .Hint + ::UIListLayout 0 false - .Hint + ::UIListLayout -1 - - - 3 - - - >TextLabel - - 0 - false - >TextLabel - -1 - - - - - - 4 - - - >ImageLabel - - 0 - false - >ImageLabel - -1 - - - - - 1 - AAAAAA== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - - + + + 0 + RBX0A0BA56913F44041AC7AC7D58D86E66B + + 0 + false + Derive from DefaultTheme + -1 + + + + - 10 - AAAAAA== + 0 + - TextLabel + .Hints 0 false - TextLabel + .Hints -1 - + - 9 - + 0 + - .Tooltip + ::UIListLayout 0 false - .Tooltip + ::UIListLayout -1 - - - 2 - - - ::UIPadding - - 0 - false - ::UIPadding - -1 - - - - - - 1 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - - - 11 - AAAAAA== - - ScrollingFrame - - 0 - false - ScrollingFrame - -1 - - - - + - 3 - + 0 + - .Surface,.Inventory + .Hint 0 false - .Surface,.Inventory + .Hint -1 - + - 1 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz + 0 + - ::UICorner + >TextLabel 0 false - ::UICorner + >TextLabel -1 - + - 2 - + 0 + - ::UIPadding + >ImageLabel 0 false - ::UIPadding + >ImageLabel -1 + + + 0 + AAAAAA== + + ::UIAspectRatioConstraint + + 0 + false + ::UIAspectRatioConstraint + -1 + + + - + - 8 - + 0 + - .Backpack + .Hotbar 0 false - .Backpack + .Hotbar -1 - + - 1 - + 0 + ::UIListLayout @@ -344,48 +282,152 @@ EQAAAFZlcnRpY2FsQWxpZ25tZW50AgAAAA==]]> - + - 6 - AAAAAA== + 0 + - ImageButton + .HintSlot 0 false - ImageButton + .HintSlot -1 + + + 0 + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== + + ::UIAspectRatioConstraint + + 0 + false + ::UIAspectRatioConstraint + -1 + + + - + 0 - RBX0A0BA56913F44041AC7AC7D58D86E66B + + + TextBox.Searchbar 0 false - Derive from DefaultTheme + TextBox.Searchbar -1 + + + 0 + + + >ImageButton + + 0 + false + >ImageButton + -1 + + + + + 1 + AAAAAA== + + ::UIAspectRatioConstraint + + 0 + false + ::UIAspectRatioConstraint + -1 + + + + + + + 0 + + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + + + + 0 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= + + ::UICorner + + 0 + false + ::UICorner + -1 + + + + + + 0 + + + ::UIStroke + + 0 + false + ::UIStroke + -1 + + + - 7 - AQAAAAsAAABMYXlvdXRPcmRlcgYAAAAAAAAAAA== + 0 + - .Inventory + Frame.Inventory 0 false - .Inventory + Frame.Inventory -1 - 1 + 0 AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA ::UIListLayout @@ -399,7 +441,7 @@ EQAAAFZlcnRpY2FsQWxpZ25tZW50AgAAAA==]]> - 1 + 0 - 2 + 0 @@ -430,251 +472,242 @@ CQAAAAAFAAAACQAAAFNvcnRPcmRlchUJAAAAU29ydE9yZGVyAgAAAAUAAABXcmFwcwMB]]> - - - - 5 - AAAAAA== - - ImageLabel - - 0 - false - ImageLabel - -1 - - - + - 1 - + 0 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz - .HintSlot + ::UICorner 0 false - .HintSlot + ::UICorner + -1 + + + + + + 0 + + + ::UIPadding + + 0 + false + ::UIPadding -1 - - - 1 - AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - + - 6 - + 0 + - .Hints + TextLabel.Tooltip 0 false - .Hints + TextLabel.Tooltip -1 - + - 1 - + 0 + - ::UIListLayout + ::UIPadding 0 false - ::UIListLayout + ::UIPadding + -1 + + + + + + 0 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz + + ::UICorner + + 0 + false + ::UICorner -1 - + - 8 - AAAAAA== + 0 + - TextButton + TextButton.Slot 0 false - TextButton + TextButton.Slot -1 - + - 2 - + 0 + AAAAAA== - .Slot + .Equipped 0 false - .Slot + .Equipped -1 - + - 10 - AAAAAA== - - .Equipped - - 0 - false - .Equipped - -1 - - - - - 1 - 0 + - - ::UIStroke - - 0 - false - ::UIStroke - -1 - - - - - - - 6 - - ::UITextSizeConstraint + ::UIStroke 0 false - ::UITextSizeConstraint + ::UIStroke -1 - - - 11 - + + + 0 + + + ::UITextSizeConstraint + + 0 + false + ::UITextSizeConstraint + -1 + + + + + + 0 + + + .Unlocked + + 0 + false + .Unlocked + -1 + + + + + 0 + AAAAAA== - .Unlocked + :Press 0 false - .Unlocked + :Press -1 - + - 9 - AAAAAA== + 0 + - :Press + ::UIStroke 0 false - :Press + ::UIStroke -1 - - - 1 - - - ::UIStroke - - 0 - false - ::UIStroke - -1 - - - - - - 7 - + + + 0 + + + >ImageLabel + + 0 + false + >ImageLabel + -1 + + + + + 0 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== - >ImageLabel + ::UICorner 0 false - >ImageLabel + ::UICorner -1 - - - 1 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - + + + + 0 + AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= + + >TextLabel + + 0 + false + >TextLabel + -1 + + + - 4 - AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= - - >TextLabel - - 0 - false - >TextLabel - -1 - - - - - 1 - 0 + - - .SlotNumber - - 0 - false - .SlotNumber - -1 - - - - - - 9 - AQAAAAcAAABWaXNpYmxlAwA= - - .Tooltip - - 0 - false - .Tooltip - -1 - - - - - - - 8 - AAAAAA== - :Hover + .SlotNumber 0 false - :Hover + .SlotNumber -1 - - - 1 - AQAAAAcAAABWaXNpYmxlAwE= - - >.Tooltip - - 0 - false - >.Tooltip - -1 - - - - + - 9 - AAAAAA== + 0 + AQAAAAcAAABWaXNpYmxlAwA= - :Press + .Tooltip 0 false - :Press - -1 - - - - - 2 - AQAAAAcAAABWaXNpYmxlAwE= - - >.Tooltip - - 0 - false - >.Tooltip - -1 - - - - - - - 1 - AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - - - 5 - - - ::UIPadding - - 0 - false - ::UIPadding + .Tooltip -1 - - - - 7 - AAAAAA== - - TextBox - - 0 - false - TextBox - -1 - - - + - 2 - + 0 + AAAAAA== - .Searchbar + :Hover 0 false - .Searchbar + :Hover -1 - - - 3 - - - >ImageButton - - 0 - false - >ImageButton - -1 - - - - - 1 - AAAAAA== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - - + - 1 - + 0 + AQAAAAcAAABWaXNpYmxlAwE= - ::UIPadding + >.Tooltip 0 false - ::UIPadding + >.Tooltip -1 - - - - 5 - - - .Hotbar - - 0 - false - .Hotbar - -1 - - - + - 1 - + 0 + AAAAAA== - ::UIListLayout + :Press 0 false - ::UIListLayout - -1 - - - - - - - 3 - - - .Container,.Searchbar - - 0 - false - .Container,.Searchbar - -1 - - - - - 2 - - - ::UIStroke - - 0 - false - ::UIStroke + :Press -1 + + + 0 + AQAAAAcAAABWaXNpYmxlAwE= + + >.Tooltip + + 0 + false + >.Tooltip + -1 + + + - + - 1 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= + 0 + AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz ::UICorner @@ -951,12 +810,12 @@ YWluZXJTdHJva2VUcmFuc3BhcmVuY3k=]]> - + - 2 - + 0 + ::UIPadding From 1f9f67b7d29374053168fb08a6d362953fae9e64 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 12 Mar 2026 19:55:13 -0700 Subject: [PATCH 065/186] Center stories Signed-off-by: Ryan Luu --- src/Stories/Satchel.storybook.luau | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Stories/Satchel.storybook.luau b/src/Stories/Satchel.storybook.luau index 563e3722..bb405c95 100644 --- a/src/Stories/Satchel.storybook.luau +++ b/src/Stories/Satchel.storybook.luau @@ -10,10 +10,13 @@ return { mapStory = function(Story) return function(storyProps) return React.createElement(React.Fragment, nil, { + UIListLayout = React.createElement("UIListLayout", { + HorizontalAlignment = Enum.HorizontalAlignment.Center, + VerticalAlignment = Enum.VerticalAlignment.Center, + }), StyleLink = React.createElement("StyleLink", { StyleSheet = DESIGN_SHEET, }), - Story = React.createElement(Story, storyProps), }) end From d5027cafe241777a5e383a1634d9786b61fcc063 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 12 Mar 2026 19:55:54 -0700 Subject: [PATCH 066/186] Use fixed size Signed-off-by: Ryan Luu --- src/Stories/Inventory.story.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Stories/Inventory.story.luau b/src/Stories/Inventory.story.luau index a3a8ce01..ea50eeb0 100644 --- a/src/Stories/Inventory.story.luau +++ b/src/Stories/Inventory.story.luau @@ -8,7 +8,7 @@ return { summary = "Toggleable inventory for displaying items not in the hotbar", story = function() return React.createElement(Inventory, { - size = UDim2.new(1, 0, 0, 320), + size = UDim2.fromOffset(655, 320), }) end, } From 071fd5b5c991eeb4cb9c9d210e731259a159bce8 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Mar 2026 16:50:41 -0700 Subject: [PATCH 067/186] Fix hotbar padding Signed-off-by: Ryan Luu --- src/Design.rbxmx | 890 ++++++++++++++++++++++++----------------------- 1 file changed, 452 insertions(+), 438 deletions(-) diff --git a/src/Design.rbxmx b/src/Design.rbxmx index 39fab8e3..5ba6adfc 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,89 +11,32 @@ -1 - + - - 0 - false - ThemeTokens - -1 - - - - - - - 0 - false - BaseTokens - -1 - - - - - 0 - RBX30E432006E76471DA6F53F0F3AF357A3 - - 0 - false - Derive from ThemeTokens - -1 - - - - - - - AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= + 0 false - DefaultTheme + LegacyTheme -1 - + 0 - RBXCD49C302BBB6416DAC42DDF502AF51D4 + RBX334BE598751E4A6EB5ABD5C6CA6DDA52 0 false @@ -103,7 +46,7 @@ VGV4dFNpemU=]]> - + 0 @@ -112,72 +55,101 @@ VGV4dFNpemU=]]> -1 - + 0 - + - .Backpack + .HintSlot 0 false - .Backpack + .HintSlot -1 - + 0 - + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== - ::UIListLayout + ::UIAspectRatioConstraint 0 false - ::UIListLayout + ::UIAspectRatioConstraint -1 - + 0 - RBX0A0BA56913F44041AC7AC7D58D86E66B + + + .Hotbar 0 false - Derive from DefaultTheme + .Hotbar -1 + + + 0 + + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + + + + 1 + AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + - + 0 - + - .Hints + .Backpack 0 false - .Hints + .Backpack -1 - + 0 - + ::UIListLayout @@ -189,7 +161,7 @@ VmVydGljYWxBbGlnbm1lbnQAAAAABQAAAFdyYXBzAwE=]]> - + 0 -1 - + 0 - + 0 -1 - + 0 AAAAAA== @@ -251,124 +223,62 @@ AAAABAAAAFNpemUKAAAAACUAAAAAAAAAJQAAAA==]]> - - - 0 - - - .Hotbar - - 0 - false - .Hotbar - -1 - - - - - 0 - - - ::UIListLayout - - 0 - false - ::UIListLayout - -1 - - - - - - - 0 - - - .HintSlot - - 0 - false - .HintSlot - -1 - - - - - 0 - AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - - + 0 - + - TextBox.Searchbar + TextButton.Slot 0 false - TextBox.Searchbar + TextButton.Slot -1 - + 0 - + AAAAAA== - >ImageButton + .Equipped 0 false - >ImageButton + .Equipped -1 - + - 1 - AAAAAA== + 0 + - ::UIAspectRatioConstraint + ::UIStroke 0 false - ::UIAspectRatioConstraint + ::UIStroke -1 - + 0 - + ::UIPadding @@ -379,10 +289,10 @@ ZwoAAABQYWRkaW5nVG9wAg4AAAAkU2VhcmNoUGFkZGluZw==]]> - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= + AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz ::UICorner @@ -393,117 +303,201 @@ ZwoAAABQYWRkaW5nVG9wAg4AAAAkU2VhcmNoUGFkZGluZw==]]> - + 0 - + AAAAAA== - ::UIStroke + :Press 0 false - ::UIStroke + :Press -1 + + + 0 + AQAAAAcAAABWaXNpYmxlAwE= + + >.Tooltip + + 0 + false + >.Tooltip + -1 + + + - - - - 0 - - - Frame.Inventory - - 0 - false - Frame.Inventory - -1 - - - + 0 - AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA + - ::UIListLayout + .Unlocked 0 false - ::UIListLayout + .Unlocked -1 + + + 0 + AAAAAA== + + :Press + + 0 + false + :Press + -1 + + + + + 0 + + + ::UIStroke + + 0 + false + ::UIStroke + -1 + + + + - + 0 - + AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= - >ScrollingFrame + >TextLabel 0 false - >ScrollingFrame + >TextLabel -1 - + 0 - + AQAAAAcAAABWaXNpYmxlAwA= - ::UIListLayout + .Tooltip 0 false - ::UIListLayout + .Tooltip + -1 + + + + + + 0 + + + .SlotNumber + + 0 + false + .SlotNumber -1 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz + - ::UICorner + ::UITextSizeConstraint 0 false - ::UICorner + ::UITextSizeConstraint -1 - + 0 - + AAAAAA== - ::UIPadding + :Hover 0 false - ::UIPadding + :Hover + -1 + + + + + 0 + AQAAAAcAAABWaXNpYmxlAwE= + + >.Tooltip + + 0 + false + >.Tooltip + -1 + + + + + + + 0 + + + >ImageLabel + + 0 + false + >ImageLabel -1 + + + 0 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== + + ::UICorner + + 0 + false + ::UICorner + -1 + + + - + 0 -1 - + 0 - + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz - ::UIPadding + ::UICorner 0 false - ::UIPadding + ::UICorner -1 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz + - ::UICorner + ::UIPadding 0 false - ::UICorner + ::UIPadding -1 - + 0 - + - TextButton.Slot + Frame.Inventory 0 false - TextButton.Slot + Frame.Inventory -1 - + 0 - AAAAAA== + - .Equipped + >ScrollingFrame 0 false - .Equipped + >ScrollingFrame -1 - + 0 - + - ::UIStroke + ::UIListLayout 0 false - ::UIStroke + ::UIListLayout -1 - + 0 - + - ::UITextSizeConstraint + ::UIPadding 0 false - ::UITextSizeConstraint + ::UIPadding -1 - + 0 - + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz - .Unlocked + ::UICorner 0 false - .Unlocked + ::UICorner -1 - - - 0 - AAAAAA== - - :Press - - 0 - false - :Press - -1 - - - - - 0 - - - ::UIStroke - - 0 - false - ::UIStroke - -1 - - - - - + 0 - + AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA - >ImageLabel + ::UIListLayout 0 false - >ImageLabel + ::UIListLayout -1 - - - 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - + + + + 0 + RBXD3008CBF651347E289B49687982E944E + + 0 + false + Derive from DefaultTheme + -1 + + + + + + 0 + + + .Hints + + 0 + false + .Hints + -1 + + + 0 - AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= + - >TextLabel + ::UIListLayout 0 false - >TextLabel + ::UIListLayout -1 - - - 0 - - - .SlotNumber - - 0 - false - .SlotNumber - -1 - - - - - - 0 - AQAAAAcAAABWaXNpYmxlAwA= - - .Tooltip - - 0 - false - .Tooltip - -1 - - - - + + + + 0 + + + TextBox.Searchbar + + 0 + false + TextBox.Searchbar + -1 + + + 0 - AAAAAA== + - :Hover + ::UIPadding 0 false - :Hover + ::UIPadding -1 - - - 0 - AQAAAAcAAABWaXNpYmxlAwE= - - >.Tooltip - - 0 - false - >.Tooltip - -1 - - - - + 0 - AAAAAA== + - :Press + ::UIStroke 0 false - :Press + ::UIStroke + -1 + + + + + + 0 + + + >ImageButton + + 0 + false + >ImageButton -1 - + - 0 - AQAAAAcAAABWaXNpYmxlAwE= + 1 + AAAAAA== - >.Tooltip + ::UIAspectRatioConstraint 0 false - >.Tooltip + ::UIAspectRatioConstraint -1 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz + AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= ::UICorner @@ -810,50 +783,21 @@ AAAAAEA=]]> - - - 0 - - - ::UIPadding - - 0 - false - ::UIPadding - -1 - - - - + - + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= 0 false - LegacyTheme + DefaultTheme -1 - + 0 - RBXCD49C302BBB6416DAC42DDF502AF51D4 + RBX334BE598751E4A6EB5ABD5C6CA6DDA52 0 false @@ -863,5 +807,75 @@ bmRDb2xvcg/NzMw+zczMPs3MzD4OAAAAVG9vbFRpcFBhZGRpbmcJAAAAAAIAAAA=]]> + + + + 0 + false + ThemeTokens + -1 + + + + + + + 0 + false + BaseTokens + -1 + + + + + 0 + RBX2E5C2075BD5446258472F8EB592F3A7A + + 0 + false + Derive from ThemeTokens + -1 + + + + \ No newline at end of file From 919dce981ee72a0cc8c0672d5b5ae73c5c57e1a8 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Mar 2026 16:54:33 -0700 Subject: [PATCH 068/186] Use custom TopbarPlus fork Signed-off-by: Ryan Luu --- wally.lock | 12 ++++++------ wally.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/wally.lock b/wally.lock index 6c2c7f94..7a45f262 100644 --- a/wally.lock +++ b/wally.lock @@ -2,11 +2,6 @@ # It is not intended for manual editing. registry = "test" -[[package]] -name = "1foreverhd/topbarplus" -version = "3.4.0" -dependencies = [] - [[package]] name = "jsdotlua/boolean" version = "1.2.7" @@ -95,4 +90,9 @@ dependencies = [["collections", "jsdotlua/collections@1.2.7"]] [[package]] name = "ryanlua/satchel" version = "1.4.1" -dependencies = [["react", "jsdotlua/react@17.2.1"], ["react-roblox", "jsdotlua/react-roblox@17.2.1"], ["topbarplus", "1foreverhd/topbarplus@3.4.0"]] +dependencies = [["react", "jsdotlua/react@17.2.1"], ["react-roblox", "jsdotlua/react-roblox@17.2.1"], ["topbarplus", "ryanlua/topbarplus@1.0.1"]] + +[[package]] +name = "ryanlua/topbarplus" +version = "1.0.1" +dependencies = [] diff --git a/wally.toml b/wally.toml index 4772f9dd..0db3d003 100644 --- a/wally.toml +++ b/wally.toml @@ -14,4 +14,4 @@ include = ["src", "src/**", "wally.toml", "wally.lock", "default.project.json", [dependencies] react = "jsdotlua/react@17.2.1" react-roblox = "jsdotlua/react-roblox@17.2.1" -topbarplus = "1foreverhd/topbarplus@3.4.0" +topbarplus = "ryanlua/topbarplus@1.0.1" From c3a8cd7f81030cc3a1017a5dfe4f84a8ee222969 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Mar 2026 16:57:38 -0700 Subject: [PATCH 069/186] Add basic topbarplus icon Signed-off-by: Ryan Luu --- src/TopbarIcon.client.luau | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/TopbarIcon.client.luau diff --git a/src/TopbarIcon.client.luau b/src/TopbarIcon.client.luau new file mode 100644 index 00000000..ff83ee71 --- /dev/null +++ b/src/TopbarIcon.client.luau @@ -0,0 +1,30 @@ +--!strict + +local Icon = require(script.Parent.Parent.topbarplus) + +local icon = Icon.new() +icon:modifyTheme({ "IconLabelContainer", "TargetWidth", 0 }) -- Force minimum width +icon:setLabel("backpack") +icon:setOrder(-1) +icon:setTextSize(24) +icon:setTextFont( + "rbxasset://LuaPackages/Packages/_Index/BuilderIcons/BuilderIcons/BuilderIcons.json", + Enum.FontWeight.Bold, + Enum.FontStyle.Normal, + "Selected" +) +icon:setTextFont( + "rbxasset://LuaPackages/Packages/_Index/BuilderIcons/BuilderIcons/BuilderIcons.json", + Enum.FontWeight.Regular, + Enum.FontStyle.Normal, + "Deselected" +) +icon:bindToggleKey(Enum.KeyCode.Backquote) +icon:autoDeselect(false) +icon:setCaption("Inventory") + +icon.toggled:Connect(function(_isSelected, fromSource) + if fromSource == "User" then + print("Inventory toggled") + end +end) From a4c56993c625f8d5372b23422b3747501ccd7fd7 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Mar 2026 17:03:50 -0700 Subject: [PATCH 070/186] Cleanup props Signed-off-by: Ryan Luu --- src/Components/Inventory.luau | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Components/Inventory.luau b/src/Components/Inventory.luau index 638a6b5d..da64b84a 100644 --- a/src/Components/Inventory.luau +++ b/src/Components/Inventory.luau @@ -5,11 +5,9 @@ local React = require(script.Parent.Parent.Parent.react) local Searchbar = require(script.Parent.Searchbar) export type Props = { - forceGamepadHintVisible: boolean?, - size: UDim2?, - slots: number?, + forceHintVisible: boolean?, + size: UDim2?, -- TODO: change size to use slots amount tools: { Tool? }?, - opened: boolean?, } local function Inventory(props: Props) From 247aa532e136063011bf388dadb0936ebe6027d7 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Mar 2026 17:44:18 -0700 Subject: [PATCH 071/186] Rename tags for hints Signed-off-by: Ryan Luu --- src/Components/HotbarHint.luau | 2 +- src/Design.rbxmx | 290 ++++++++++++++++----------------- 2 files changed, 146 insertions(+), 146 deletions(-) diff --git a/src/Components/HotbarHint.luau b/src/Components/HotbarHint.luau index 6f155e12..c456ff74 100644 --- a/src/Components/HotbarHint.luau +++ b/src/Components/HotbarHint.luau @@ -41,7 +41,7 @@ local function HotbarHint(props: Props) Image = UserInputService:GetImageForKeyCode(props.keyCode), LayoutOrder = props.order, Visible = visible, - [React.Tag] = "HintSlot", + [React.Tag] = "HotbarHint", }) end diff --git a/src/Design.rbxmx b/src/Design.rbxmx index 5ba6adfc..fd5101cc 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,7 +11,7 @@ -1 - + -1 - + 0 - RBX334BE598751E4A6EB5ABD5C6CA6DDA52 + RBX622E8FEB25794E9FBA6DCC6497F2710E 0 false @@ -46,7 +46,7 @@ bmRDb2xvcg/NzMw+zczMPs3MzD4OAAAAVG9vbFRpcFBhZGRpbmcJAAAAAAIAAAA=]]> - + 0 @@ -55,36 +55,7 @@ bmRDb2xvcg/NzMw+zczMPs3MzD4OAAAAVG9vbFRpcFBhZGRpbmcJAAAAAAIAAAA=]]>-1 - - - 0 - - - .HintSlot - - 0 - false - .HintSlot - -1 - - - - - 0 - AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - - + 0 -1 - + 0 - + 1 AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= @@ -129,7 +100,7 @@ aWdubWVudBURAAAAVmVydGljYWxBbGlnbm1lbnQAAAAA]]> - + 0 -1 - + 0 - - - 0 - - - .Hint - - 0 - false - .Hint - -1 - - - - - 0 - - - >TextLabel - - 0 - false - >TextLabel - -1 - - - - - - 0 - - - >ImageLabel - - 0 - false - >ImageLabel - -1 - - - - - 0 - AAAAAA== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - - - + 0 -1 - + 0 AAAAAA== @@ -255,7 +164,7 @@ cmFuc3BhcmVuY3kMAAAAVGV4dFRydW5jYXRlFQwAAABUZXh0VHJ1bmNhdGUCAAAA]]>-1 - + 0 - + 0 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz @@ -303,7 +212,7 @@ YWRkaW5nVG9wAgwAAAAkU2xvdFBhZGRpbmc=]]> - + 0 AAAAAA== @@ -316,7 +225,7 @@ YWRkaW5nVG9wAgwAAAAkU2xvdFBhZGRpbmc=]]> -1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -331,7 +240,7 @@ YWRkaW5nVG9wAgwAAAAkU2xvdFBhZGRpbmc=]]> - + 0 -1 - + 0 AAAAAA== @@ -358,7 +267,7 @@ chYAAABCYWNrZ3JvdW5kVHJhbnNwYXJlbmN5BgAAAAAAAAAA]]> -1 - + 0 - + 0 AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= @@ -388,7 +297,7 @@ b3ICFQAAACRTbG90UHJlc3NTdHJva2VDb2xvcgkAAABUaGlja25lc3MGAAAAAAAAAEA=]]>-1 - + 0 AQAAAAcAAABWaXNpYmxlAwA= @@ -402,7 +311,7 @@ b3ICFQAAACRTbG90UHJlc3NTdHJva2VDb2xvcgkAAABUaGlja25lc3MGAAAAAAAAAEA=]]> - + 0 - + 0 - + 0 AAAAAA== @@ -452,7 +361,7 @@ AAAAAAAoQA==]]> -1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -467,7 +376,7 @@ AAAAAAAoQA==]]> - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== @@ -497,7 +406,7 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz @@ -530,7 +439,7 @@ ZXh0U2l6ZQ==]]> - + 0 - + 0 -1 - + 0 -1 - + 0 - + 0 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz @@ -625,7 +534,7 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkU3VyZmFjZVBhZGRpbmc=]]> - + 0 AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA @@ -640,10 +549,10 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkU3VyZmFjZVBhZGRpbmc=]]> - + 0 - RBXD3008CBF651347E289B49687982E944E + RBXEDAAA25B3FFA4BE78C974E3F365F7B1E 0 false @@ -652,7 +561,7 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkU3VyZmFjZVBhZGRpbmc=]]> - + 0 -1 - + 0 - + 0 -1 - + 0 - + 0 - + 0 -1 - + 1 AAAAAA== @@ -769,7 +678,7 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAAcAAABWaXNpYmxlAwA=]]> - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= @@ -784,8 +693,99 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAAcAAABWaXNpYmxlAwA=]]> + + + 0 + + + .InventoryHint + + 0 + false + .InventoryHint + -1 + + + + + 0 + + + >TextLabel + + 0 + false + >TextLabel + -1 + + + + + + 0 + + + >ImageLabel + + 0 + false + >ImageLabel + -1 + + + + + 0 + AAAAAA== + + ::UIAspectRatioConstraint + + 0 + false + ::UIAspectRatioConstraint + -1 + + + + + + + + 0 + + + .HotbarHint + + 0 + false + .HotbarHint + -1 + + + + + 0 + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== + + ::UIAspectRatioConstraint + + 0 + false + ::UIAspectRatioConstraint + -1 + + + + - + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= 0 @@ -794,10 +794,10 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAAcAAABWaXNpYmxlAwA=]]> -1 - + 0 - RBX334BE598751E4A6EB5ABD5C6CA6DDA52 + RBX622E8FEB25794E9FBA6DCC6497F2710E 0 false @@ -807,7 +807,7 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAAcAAABWaXNpYmxlAwA=]]> - + - + -1 - + 0 - RBX2E5C2075BD5446258472F8EB592F3A7A + RBXC0911E6382414FCDA2ED408DA296DA2B 0 false From 0c210a3a779b0d2e8b711b57c2a6ca14f97409a5 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Mar 2026 17:53:07 -0700 Subject: [PATCH 072/186] Fix hint image background transparency Signed-off-by: Ryan Luu --- src/Design.rbxmx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Design.rbxmx b/src/Design.rbxmx index fd5101cc..3dac178b 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -728,8 +728,9 @@ bG9yCAAAAFRleHRTaXplAg0AAAAkSGludFRleHRTaXpl]]> 0 - + >ImageLabel From 48b7119dcf937aec025482f1a6e8857b72b0098b Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Mar 2026 17:56:27 -0700 Subject: [PATCH 073/186] Fix sizing for hint images Signed-off-by: Ryan Luu --- src/Design.rbxmx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Design.rbxmx b/src/Design.rbxmx index 3dac178b..813839d1 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -728,9 +728,9 @@ bG9yCAAAAFRleHRTaXplAg0AAAAkSGludFRleHRTaXpl]]> 0 - + >ImageLabel @@ -740,10 +740,10 @@ AAAAAAAlAAAA]]> -1 - + 0 - AAAAAA== + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== ::UIAspectRatioConstraint From 7ba1addae28386144a2f2a1b56337d6ead6ea5bb Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Mar 2026 17:57:42 -0700 Subject: [PATCH 074/186] Add inventory hint component Signed-off-by: Ryan Luu --- src/Components/InventoryHint.luau | 55 ++++++++++++++++++++++++++++ src/Stories/InventoryHint.story.luau | 26 +++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 src/Components/InventoryHint.luau create mode 100644 src/Stories/InventoryHint.story.luau diff --git a/src/Components/InventoryHint.luau b/src/Components/InventoryHint.luau new file mode 100644 index 00000000..19714948 --- /dev/null +++ b/src/Components/InventoryHint.luau @@ -0,0 +1,55 @@ +--!strict + +local UserInputService = game:GetService("UserInputService") + +local React = require(script.Parent.Parent.Parent.react) + +export type Props = { + keyCode: Enum.KeyCode, + text: string, + forceVisible: boolean?, + order: number?, +} + +local function InventoryHint(props: Props) + -- Only show hint if gamepad is preferred or forced visible + local isGamepadPreferred, setIsGamepadPreferred = + React.useState(UserInputService.PreferredInput == Enum.PreferredInput.Gamepad) + + React.useEffect(function() + local function preferredInputChanged() + local preferredInput = UserInputService.PreferredInput + + if preferredInput == Enum.PreferredInput.Gamepad then + setIsGamepadPreferred(true) + else + setIsGamepadPreferred(false) + end + end + + preferredInputChanged() + local signal: RBXScriptConnection = UserInputService:GetPropertyChangedSignal("PreferredInput") + :Connect(preferredInputChanged) + + return function() + signal:Disconnect() + end + end, {}) + + local visible = props.forceVisible or isGamepadPreferred + + return React.createElement("Frame", { + LayoutOrder = props.order, + Visible = visible, + [React.Tag] = "InventoryHint", + }, { + React.createElement("ImageLabel", { + Image = UserInputService:GetImageForKeyCode(props.keyCode), + }), + React.createElement("TextLabel", { + Text = props.text, + }), + }) +end + +return InventoryHint diff --git a/src/Stories/InventoryHint.story.luau b/src/Stories/InventoryHint.story.luau new file mode 100644 index 00000000..856f4e2e --- /dev/null +++ b/src/Stories/InventoryHint.story.luau @@ -0,0 +1,26 @@ +--!strict + +local React = require(script.Parent.Parent.Parent.react) + +local InventoryHint = require(script.Parent.Parent.Components.InventoryHint) + +local controls = { + text = "Remove from Hotbar", +} + +type Props = { + controls: typeof(controls), +} + +return { + name = "Inventory Hint", + summary = "Hint shown in the inventory", + controls = controls, + story = function(props: Props) + return React.createElement(InventoryHint, { + keyCode = Enum.KeyCode.ButtonX, + forceVisible = true, + text = props.controls.text, + }) + end, +} From 3b3657294c8b6483b8bd2d7b30ed3fe5ac52bae6 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Mar 2026 18:00:53 -0700 Subject: [PATCH 075/186] Rename context to indicate inventory Signed-off-by: Ryan Luu --- .../{BackpackContext.model.json => InventoryContext.model.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Bindings/{BackpackContext.model.json => InventoryContext.model.json} (100%) diff --git a/src/Bindings/BackpackContext.model.json b/src/Bindings/InventoryContext.model.json similarity index 100% rename from src/Bindings/BackpackContext.model.json rename to src/Bindings/InventoryContext.model.json From 502dfdc8e4775d5d869440e9d13200d61aa298d7 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Mar 2026 18:57:02 -0700 Subject: [PATCH 076/186] Cleanup hint styling Signed-off-by: Ryan Luu --- src/Design.rbxmx | 806 +++++++++++++++++++++++------------------------ 1 file changed, 403 insertions(+), 403 deletions(-) diff --git a/src/Design.rbxmx b/src/Design.rbxmx index 813839d1..03db03b6 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,32 +11,19 @@ -1 - + - + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= 0 false - LegacyTheme + DefaultTheme -1 - + 0 - RBX622E8FEB25794E9FBA6DCC6497F2710E + RBX72FEF53A89C240B48560FD3AD33728DE 0 false @@ -46,7 +33,7 @@ bmRDb2xvcg/NzMw+zczMPs3MzD4OAAAAVG9vbFRpcFBhZGRpbmcJAAAAAAIAAAA=]]> - + 0 @@ -55,26 +42,28 @@ bmRDb2xvcg/NzMw+zczMPs3MzD4OAAAAVG9vbFRpcFBhZGRpbmcJAAAAAAIAAAA=]]>-1 - + 0 - + - .Hotbar + .Hints 0 false - .Hotbar + .Hints -1 - + 0 - + ::UIListLayout @@ -85,10 +74,32 @@ aWdubWVudBURAAAAVmVydGljYWxBbGlnbm1lbnQAAAAA]]> - + + + + 0 + + + TextLabel.Tooltip + + 0 + false + TextLabel.Tooltip + -1 + + + - 1 - AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= + 0 + ::UIPadding @@ -99,28 +110,41 @@ aWdubWVudBURAAAAVmVydGljYWxBbGlnbm1lbnQAAAAA]]> + + + 0 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz + + ::UICorner + + 0 + false + ::UICorner + -1 + + + - + 0 - + - .Backpack + .Hotbar 0 false - .Backpack + .Hotbar -1 - + 0 - + ::UIListLayout @@ -131,77 +155,109 @@ EQAAAFZlcnRpY2FsQWxpZ25tZW50AgAAAA==]]> + + + 1 + AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + - + 0 - + - TextButton.Slot + .InventoryHint 0 false - TextButton.Slot + .InventoryHint -1 - + 0 - AAAAAA== + - .Equipped + >ImageLabel 0 false - .Equipped + >ImageLabel -1 - + 0 - + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== - ::UIStroke + ::UIAspectRatioConstraint 0 false - ::UIStroke + ::UIAspectRatioConstraint -1 - + 0 - + - ::UIPadding + >TextLabel 0 false - ::UIPadding + >TextLabel -1 - + + + + 0 + + + TextBox.Searchbar + + 0 + false + TextBox.Searchbar + -1 + + + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz + AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= ::UICorner @@ -212,318 +268,249 @@ YWRkaW5nVG9wAgwAAAAkU2xvdFBhZGRpbmc=]]> - + 0 - AAAAAA== + - :Press + ::UIPadding 0 false - :Press + ::UIPadding -1 - - - 0 - AQAAAAcAAABWaXNpYmxlAwE= - - >.Tooltip - - 0 - false - >.Tooltip - -1 - - - - + 0 - + - .Unlocked + ::UIStroke 0 false - .Unlocked + ::UIStroke + -1 + + + + + + 0 + + + >ImageButton + + 0 + false + >ImageButton -1 - + - 0 + 1 AAAAAA== - :Press + ::UIAspectRatioConstraint 0 false - :Press + ::UIAspectRatioConstraint -1 - - - 0 - - - ::UIStroke - - 0 - false - ::UIStroke - -1 - - - - + + + + 0 + + + .Inventory + + 0 + false + .Inventory + -1 + + + 0 - AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= + - >TextLabel + >ScrollingFrame 0 false - >TextLabel + >ScrollingFrame -1 - + 0 - AQAAAAcAAABWaXNpYmxlAwA= + - .Tooltip + ::UIListLayout 0 false - .Tooltip - -1 - - - - - - 0 - - - .SlotNumber - - 0 - false - .SlotNumber + ::UIListLayout -1 - + 0 - + - ::UITextSizeConstraint + ::UIPadding 0 false - ::UITextSizeConstraint + ::UIPadding -1 - + 0 - AAAAAA== + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz - :Hover + ::UICorner 0 false - :Hover + ::UICorner -1 - - - 0 - AQAAAAcAAABWaXNpYmxlAwE= - - >.Tooltip - - 0 - false - >.Tooltip - -1 - - - - + 0 - + AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA - >ImageLabel + ::UIListLayout 0 false - >ImageLabel + ::UIListLayout -1 - - - 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - + 0 - + - TextLabel.Tooltip + .Backpack 0 false - TextLabel.Tooltip + .Backpack -1 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - - - 0 - + - ::UIPadding + ::UIListLayout 0 false - ::UIPadding + ::UIListLayout -1 - + 0 - + - Frame.Inventory + TextButton.Slot 0 false - Frame.Inventory + TextButton.Slot -1 - + 0 - + - >ScrollingFrame + ::UIPadding 0 false - >ScrollingFrame + ::UIPadding -1 - - - 0 - - - ::UIListLayout - - 0 - false - ::UIListLayout - -1 - - - - + 0 - + - ::UIPadding + ::UITextSizeConstraint 0 false - ::UIPadding + ::UITextSizeConstraint -1 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz + AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz ::UICorner @@ -534,229 +521,217 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkU3VyZmFjZVBhZGRpbmc=]]> - + 0 - AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA + AAAAAA== - ::UIListLayout + :Press 0 false - ::UIListLayout + :Press -1 + + + 0 + AQAAAAcAAABWaXNpYmxlAwE= + + >.Tooltip + + 0 + false + >.Tooltip + -1 + + + - - - - 0 - RBXEDAAA25B3FFA4BE78C974E3F365F7B1E - - 0 - false - Derive from DefaultTheme - -1 - - - - - - 0 - - - .Hints - - 0 - false - .Hints - -1 - - - + 0 - + AAAAAA== - ::UIListLayout + :Hover 0 false - ::UIListLayout + :Hover -1 + + + 0 + AQAAAAcAAABWaXNpYmxlAwE= + + >.Tooltip + + 0 + false + >.Tooltip + -1 + + + - - - - 0 - - - TextBox.Searchbar - - 0 - false - TextBox.Searchbar - -1 - - - + 0 - + - ::UIPadding + >ImageLabel 0 false - ::UIPadding + >ImageLabel -1 + + + 0 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== + + ::UICorner + + 0 + false + ::UICorner + -1 + + + - + 0 - + AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= - ::UIStroke + >TextLabel 0 false - ::UIStroke + >TextLabel -1 + + + 0 + AQAAAAcAAABWaXNpYmxlAwA= + + .Tooltip + + 0 + false + .Tooltip + -1 + + + + + + 0 + + + .SlotNumber + + 0 + false + .SlotNumber + -1 + + + - + 0 - + - >ImageButton + .Unlocked 0 false - >ImageButton + .Unlocked -1 - + - 1 + 0 AAAAAA== - ::UIAspectRatioConstraint + :Press 0 false - ::UIAspectRatioConstraint + :Press -1 + + + 0 + + + ::UIStroke + + 0 + false + ::UIStroke + -1 + + + - - - 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - - - - 0 - - - .InventoryHint - - 0 - false - .InventoryHint - -1 - - - - - 0 - - - >TextLabel - - 0 - false - >TextLabel - -1 - - - - + 0 - + AAAAAA== - >ImageLabel + .Equipped 0 false - >ImageLabel + .Equipped -1 - + 0 - AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== + - ::UIAspectRatioConstraint + ::UIStroke 0 false - ::UIAspectRatioConstraint + ::UIStroke -1 - + 0 -1 - + 0 AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== @@ -785,20 +760,45 @@ AAAAU2NhbGVUeXBlAwAAAAQAAABTaXplCgAAAAA8AAAAAAAAADwAAAA=]]> + + + 0 + RBX8F98C2C8B5EC4CFDB34EE6AF29A919D9 + + 0 + false + Derive from DefaultTheme + -1 + + + - + - AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= + 0 false - DefaultTheme + LegacyTheme -1 - + 0 - RBX622E8FEB25794E9FBA6DCC6497F2710E + RBX72FEF53A89C240B48560FD3AD33728DE 0 false @@ -808,7 +808,7 @@ AAAAU2NhbGVUeXBlAwAAAAQAAABTaXplCgAAAAA8AAAAAAAAADwAAAA=]]> - + - + -1 - + 0 - RBXC0911E6382414FCDA2ED408DA296DA2B + RBX210796792ED44C7495D12F29536A2DB9 0 false From 31aac1ed226a012a7ada10d19f85d543290ae3d0 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Mar 2026 21:01:45 -0700 Subject: [PATCH 077/186] Add basic inventory component Signed-off-by: Ryan Luu --- src/Components/Inventory.luau | 33 +++- src/Design.rbxmx | 304 +++++++++++++++++-------------- src/Stories/Inventory.story.luau | 25 ++- 3 files changed, 221 insertions(+), 141 deletions(-) diff --git a/src/Components/Inventory.luau b/src/Components/Inventory.luau index da64b84a..802a0657 100644 --- a/src/Components/Inventory.luau +++ b/src/Components/Inventory.luau @@ -2,8 +2,14 @@ local React = require(script.Parent.Parent.Parent.react) +local InventoryHint = require(script.Parent.InventoryHint) local Searchbar = require(script.Parent.Searchbar) +local InventoryBindings = script.Parent.Parent.Bindings.InventoryContext +local RemoveFromHotbarGamepadKeyCode = InventoryBindings.RemoveFromHotbarAction.GamepadBinding.KeyCode +local SelectSwapGamepadKeyCode = InventoryBindings.SelectSwapAction.GamepadBinding.KeyCode +local CloseInventoryGamepadKeyCode = InventoryBindings.CloseInventoryAction.GamepadBinding.KeyCode + export type Props = { forceHintVisible: boolean?, size: UDim2?, -- TODO: change size to use slots amount @@ -15,8 +21,31 @@ local function Inventory(props: Props) Size = props.size, [React.Tag] = "Inventory", }, { - SearchBox = React.createElement(Searchbar), - SlotFrame = React.createElement("ScrollingFrame"), + Hints = React.createElement("Frame", { + [React.Tag] = "Hints", + }, { + RemoveFromHotbarHint = React.createElement(InventoryHint, { + keyCode = RemoveFromHotbarGamepadKeyCode, + forceVisible = props.forceHintVisible, + text = "Remove from hotbar", + }), + SelectSwapHint = React.createElement(InventoryHint, { + keyCode = SelectSwapGamepadKeyCode, + forceVisible = props.forceHintVisible, + text = "Select/Swap", + }), + CloseInventoryHint = React.createElement(InventoryHint, { + keyCode = CloseInventoryGamepadKeyCode, + forceVisible = props.forceHintVisible, + text = "Close inventory", + }), + }), + Slots = React.createElement("Frame", { + [React.Tag] = "Slots", + }, { + SearchBox = React.createElement(Searchbar), + SlotFrame = React.createElement("ScrollingFrame"), + }), }) end diff --git a/src/Design.rbxmx b/src/Design.rbxmx index 03db03b6..4d01988a 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,7 +11,7 @@ -1 - + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= 0 @@ -20,10 +20,10 @@ -1 - + 0 - RBX72FEF53A89C240B48560FD3AD33728DE + RBX2C62B177C69A499883D8BD697CD45A18 0 false @@ -33,7 +33,7 @@ - + 0 @@ -42,12 +42,11 @@ -1 - + 0 - + .Hints @@ -57,13 +56,12 @@ emUKAAAAAAAAAAAAAAAAAAAAAA==]]> -1 - + 0 - +RmxleBUPAAAAVUlGbGV4QWxpZ25tZW50BAAAAAUAAABXcmFwcwMB]]> ::UIListLayout @@ -75,7 +73,7 @@ VmVydGljYWxBbGlnbm1lbnQAAAAABQAAAFdyYXBzAwE=]]> - + 0 -1 - + 0 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz @@ -125,7 +123,7 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkVG9vbFRpcFBhZGRpbmc=]]> - + 0 -1 - + 0 - + - 1 + 0 AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= ::UIPadding @@ -170,7 +168,7 @@ aWdubWVudBURAAAAVmVydGljYWxBbGlnbm1lbnQAAAAA]]> - + 0 -1 - + 0 -1 - + 0 AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== @@ -214,14 +212,14 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAAAAACUAAAAAAAAAJQAAAA==]]> - + 0 - +bnRGYWNlAg0AAAAkSGludEZvbnRGYWNlCAAAAFBvc2l0aW9uCgAAAAAqAAAAAAAAPwAAAAAK +AAAAVGV4dENvbG9yMwIOAAAAJEhpbnRUZXh0Q29sb3IIAAAAVGV4dFNpemUCDQAAACRIaW50 +VGV4dFNpemU=]]> >TextLabel @@ -233,7 +231,7 @@ bG9yCAAAAFRleHRTaXplAg0AAAAkSGludFRleHRTaXpl]]> - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= @@ -268,7 +266,7 @@ dBUOAAAAVGV4dFhBbGlnbm1lbnQAAAAA]]> - + 0 - + 0 - + 0 -1 - + - 1 + 0 AAAAAA== ::UIAspectRatioConstraint @@ -332,55 +330,23 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAAcAAABWaXNpYmxlAwA=]]> - + 0 - + - .Inventory + .Slots 0 false - .Inventory + .Slots -1 - - - 0 - - - >ScrollingFrame - - 0 - false - >ScrollingFrame - -1 - - - - - 0 - - - ::UIListLayout - - 0 - false - ::UIListLayout - -1 - - - - - + 0 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz @@ -410,7 +376,7 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkU3VyZmFjZVBhZGRpbmc=]]> - + 0 AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA @@ -424,12 +390,45 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkU3VyZmFjZVBhZGRpbmc=]]> + + + 0 + + + >ScrollingFrame + + 0 + false + >ScrollingFrame + -1 + + + + + 0 + + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + + - + 0 .Backpack @@ -440,7 +439,7 @@ c2l0aW9uCgAAAD8AAAAAAACAPwAAAAA=]]> -1 - + 0 - + 0 -1 - + 0 - + 0 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz @@ -521,7 +520,7 @@ AAAAAAAoQA==]]> - + 0 AAAAAA== @@ -534,35 +533,7 @@ AAAAAAAoQA==]]> -1 - - - 0 - AQAAAAcAAABWaXNpYmxlAwE= - - >.Tooltip - - 0 - false - >.Tooltip - -1 - - - - - - - 0 - AAAAAA== - - :Hover - - 0 - false - :Hover - -1 - - - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -577,7 +548,7 @@ AAAAAAAoQA==]]> - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== @@ -606,7 +577,7 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> - + 0 AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= @@ -619,7 +590,7 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> -1 - + 0 AQAAAAcAAABWaXNpYmxlAwA= @@ -633,17 +604,16 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> - + 0 - +AAAAVGV4dFlBbGlnbm1lbnQVDgAAAFRleHRZQWxpZ25tZW50AAAAAA==]]> .SlotNumber @@ -655,7 +625,7 @@ AAAAAEA=]]> - + 0 -1 - + 0 AAAAAA== @@ -682,7 +652,7 @@ chYAAABCYWNrZ3JvdW5kVHJhbnNwYXJlbmN5BgAAAAAAAAAA]]> -1 - + 0 - + 0 AAAAAA== @@ -712,7 +682,7 @@ b3ICFQAAACRTbG90UHJlc3NTdHJva2VDb2xvcgkAAABUaGlja25lc3MGAAAAAAAAAEA=]]>-1 - + 0 + + + 0 + AAAAAA== + + :Hover + + 0 + false + :Hover + -1 + + + + + 0 + AQAAAAcAAABWaXNpYmxlAwE= + + >.Tooltip + + 0 + false + >.Tooltip + -1 + + + + - + 0 -1 - + 0 AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== @@ -760,10 +758,10 @@ AAAAU2NhbGVUeXBlAwAAAAQAAABTaXplCgAAAAA8AAAAAAAAADwAAAA=]]> - + 0 - RBX8F98C2C8B5EC4CFDB34EE6AF29A919D9 + RBXE8D4E040BBA44A1A8622D7DCF93A7585 0 false @@ -772,8 +770,38 @@ AAAAU2NhbGVUeXBlAwAAAAQAAABTaXplCgAAAAA8AAAAAAAAADwAAAA=]]> + + + 0 + + + .Inventory + + 0 + false + .Inventory + -1 + + + + + 0 + AAAAAA== + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + + - + -1 - + 0 - RBX72FEF53A89C240B48560FD3AD33728DE + RBX2C62B177C69A499883D8BD697CD45A18 0 false @@ -808,7 +836,7 @@ bmRDb2xvcg/NzMw+zczMPs3MzD4OAAAAVG9vbFRpcFBhZGRpbmcJAAAAAAIAAAA=]]> - + - + -1 - + 0 - RBX210796792ED44C7495D12F29536A2DB9 + RBX0E1020DB074E4CFDB870DC4566DC7B5E 0 false diff --git a/src/Stories/Inventory.story.luau b/src/Stories/Inventory.story.luau index ea50eeb0..1e81e994 100644 --- a/src/Stories/Inventory.story.luau +++ b/src/Stories/Inventory.story.luau @@ -4,11 +4,34 @@ local React = require(script.Parent.Parent.Parent.react) local Inventory = require(script.Parent.Parent.Components.Inventory) +local controls = { + hintVisible = true, + toolName = "Sword", + toolImage = "rbxasset://Textures/Sword128.png", + tooltipText = "A classic sword", + toolSlot = 1, +} + +type Props = { + controls: typeof(controls), +} + return { summary = "Toggleable inventory for displaying items not in the hotbar", - story = function() + controls = controls, + story = function(props: Props) + local tool = Instance.new("Tool") + tool.Name = props.controls.toolName + tool.TextureId = props.controls.toolImage + tool.ToolTip = props.controls.tooltipText + + local tools = {} + tools[props.controls.toolSlot] = tool + return React.createElement(Inventory, { + forceHintVisible = props.controls.hintVisible, size = UDim2.fromOffset(655, 320), + tools = tools, }) end, } From 5a017a120eeb9453434ea82b4d3b4a8c69c73a65 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Mar 2026 21:24:04 -0700 Subject: [PATCH 078/186] Add prop for showing keyboard hint Signed-off-by: Ryan Luu --- src/Components/Slot.luau | 6 ++---- src/Stories/Slot.story.luau | 2 ++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Components/Slot.luau b/src/Components/Slot.luau index ce976afa..d16d13db 100644 --- a/src/Components/Slot.luau +++ b/src/Components/Slot.luau @@ -11,6 +11,7 @@ export type Props = { equipped: boolean?, unlocked: boolean?, forceHintVisible: boolean?, + hint: boolean?, order: number?, } @@ -53,7 +54,7 @@ local function Slot(props: Props) end end, {}) - local hintVisible = props.forceHintVisible or isKeyboardPreferred + local hintVisible = props.hint == true and (props.forceHintVisible or isKeyboardPreferred) -- Generate tags based on state local tags = "Slot" @@ -74,9 +75,6 @@ local function Slot(props: Props) Text = slotText, LayoutOrder = props.order, [React.Tag] = tags, - [React.Event.Activated] = function() - print("Slot activated") - end, }, { NumberHint = React.createElement("TextLabel", { Text = slotNumber, diff --git a/src/Stories/Slot.story.luau b/src/Stories/Slot.story.luau index b92136dd..c5f52785 100644 --- a/src/Stories/Slot.story.luau +++ b/src/Stories/Slot.story.luau @@ -10,6 +10,7 @@ local controls = { toolTooltip = "A classic sword", equipped = false, unlocked = false, + hint = true, order = 1, } @@ -30,6 +31,7 @@ return { tool = Tool, equipped = props.controls.equipped, unlocked = props.controls.unlocked, + hint = props.controls.hint, order = props.controls.order, }) end, From e8447aa2b2c2d182ab916b2353640566f1b41cd8 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Mar 2026 21:25:22 -0700 Subject: [PATCH 079/186] Add inventory slot logic Signed-off-by: Ryan Luu --- src/Components/Hotbar.luau | 1 + src/Components/Inventory.luau | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Components/Hotbar.luau b/src/Components/Hotbar.luau index 9bff196f..dca09b83 100644 --- a/src/Components/Hotbar.luau +++ b/src/Components/Hotbar.luau @@ -31,6 +31,7 @@ local function Hotbar(props: Props) children[slotNumber] = React.createElement(Slot, { order = slotNumber, tool = tool, + hint = true, forceHintVisible = props.forceKeyboardHintVisible, unlocked = slotUnlocked, }) diff --git a/src/Components/Inventory.luau b/src/Components/Inventory.luau index 802a0657..b3743032 100644 --- a/src/Components/Inventory.luau +++ b/src/Components/Inventory.luau @@ -4,6 +4,7 @@ local React = require(script.Parent.Parent.Parent.react) local InventoryHint = require(script.Parent.InventoryHint) local Searchbar = require(script.Parent.Searchbar) +local Slot = require(script.Parent.Slot) local InventoryBindings = script.Parent.Parent.Bindings.InventoryContext local RemoveFromHotbarGamepadKeyCode = InventoryBindings.RemoveFromHotbarAction.GamepadBinding.KeyCode @@ -17,6 +18,20 @@ export type Props = { } local function Inventory(props: Props) + local slotChildren = {} + + if props.tools then + for order, tool in props.tools do + if tool then + slotChildren[order] = React.createElement(Slot, { + unlocked = true, + order = order, + tool = tool, + }) + end + end + end + return React.createElement("Frame", { Size = props.size, [React.Tag] = "Inventory", @@ -44,7 +59,7 @@ local function Inventory(props: Props) [React.Tag] = "Slots", }, { SearchBox = React.createElement(Searchbar), - SlotFrame = React.createElement("ScrollingFrame"), + SlotFrame = React.createElement("ScrollingFrame", nil, slotChildren), }), }) end From 0cb86ad8eac083d90385be1d2b28e18bb39d1660 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Mar 2026 21:25:53 -0700 Subject: [PATCH 080/186] Add basic inventory to backpack Signed-off-by: Ryan Luu --- src/Components/Backpack.luau | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Components/Backpack.luau b/src/Components/Backpack.luau index 7b17cdc8..be05a9df 100644 --- a/src/Components/Backpack.luau +++ b/src/Components/Backpack.luau @@ -2,6 +2,7 @@ local React = require(script.Parent.Parent.Parent.react) +local Inventory = require(script.Parent.Inventory) local Hotbar = require(script.Parent.Hotbar) export type Props = { @@ -23,6 +24,13 @@ local function Backpack(props: Props) tools = props.tools, opened = props.opened, }), + Inventory = React.createElement(Inventory, { + forceGamepadHintVisible = props.forceGamepadHintVisible, + forceKeyboardHintVisible = props.forceKeyboardHintVisible, + slots = props.slots, + tools = props.tools, + opened = props.opened, + }), }) end From 2302f22f2af6d1de51efcb85f2f28946d318700a Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 14 Mar 2026 01:01:42 -0700 Subject: [PATCH 081/186] Improve slots scrolling Signed-off-by: Ryan Luu --- src/Design.rbxmx | 136 ++++++++++++++++++++++++----------------------- 1 file changed, 69 insertions(+), 67 deletions(-) diff --git a/src/Design.rbxmx b/src/Design.rbxmx index 4d01988a..19b96c85 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,7 +11,7 @@ -1 - + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= 0 @@ -20,10 +20,10 @@ -1 - + 0 - RBX2C62B177C69A499883D8BD697CD45A18 + RBX6DFAD72BC8234139AAAA97B340E0B522 0 false @@ -33,7 +33,7 @@ - + 0 @@ -42,7 +42,7 @@ -1 - + 0 -1 - + 0 - + 0 -1 - + 0 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz @@ -123,7 +123,7 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkVG9vbFRpcFBhZGRpbmc=]]> - + 0 -1 - + 0 - + 0 AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= @@ -168,7 +168,7 @@ aWdubWVudBURAAAAVmVydGljYWxBbGlnbm1lbnQAAAAA]]> - + 0 -1 - + 0 -1 - + 0 AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== @@ -212,7 +212,7 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAAAAACUAAAAAAAAAJQAAAA==]]> - + 0 - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= @@ -266,7 +266,7 @@ dBUOAAAAVGV4dFhBbGlnbm1lbnQAAAAA]]> - + 0 - + 0 - + 0 -1 - + 0 AAAAAA== @@ -330,7 +330,7 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAAcAAABWaXNpYmxlAwA=]]> - + 0 -1 - + 0 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz @@ -376,7 +376,7 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkU3VyZmFjZVBhZGRpbmc=]]> - + 0 AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA @@ -390,14 +390,16 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkU3VyZmFjZVBhZGRpbmc=]]> - + 0 - + >ScrollingFrame @@ -407,7 +409,7 @@ AAAAAP8AAAA=]]> -1 - + 0 - + 0 -1 - + 0 - + 0 -1 - + 0 - + 0 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz @@ -520,7 +522,7 @@ AAAAAAAoQA==]]> - + 0 AAAAAA== @@ -533,7 +535,7 @@ AAAAAAAoQA==]]> -1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -548,7 +550,7 @@ AAAAAAAoQA==]]> - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== @@ -577,7 +579,7 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> - + 0 AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= @@ -590,7 +592,7 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> -1 - + 0 AQAAAAcAAABWaXNpYmxlAwA= @@ -604,7 +606,7 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> - + 0 - + 0 -1 - + 0 AAAAAA== @@ -652,7 +654,7 @@ chYAAABCYWNrZ3JvdW5kVHJhbnNwYXJlbmN5BgAAAAAAAAAA]]> -1 - + 0 - + 0 AAAAAA== @@ -682,7 +684,7 @@ b3ICFQAAACRTbG90UHJlc3NTdHJva2VDb2xvcgkAAABUaGlja25lc3MGAAAAAAAAAEA=]]>-1 - + 0 - + 0 AAAAAA== @@ -713,7 +715,7 @@ b2luTW9kZQAAAAAJAAAAVGhpY2tuZXNzAhkAAAAkU2xvdEVxdWlwU3Ryb2tlVGhpY2tuZXNz -1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -729,7 +731,7 @@ b2luTW9kZQAAAAAJAAAAVGhpY2tuZXNzAhkAAAAkU2xvdEVxdWlwU3Ryb2tlVGhpY2tuZXNz - + 0 -1 - + 0 AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== @@ -758,10 +760,10 @@ AAAAU2NhbGVUeXBlAwAAAAQAAABTaXplCgAAAAA8AAAAAAAAADwAAAA=]]> - + 0 - RBXE8D4E040BBA44A1A8622D7DCF93A7585 + RBX39C4CD6CC7364378BD7D7EC698DF3F46 0 false @@ -770,7 +772,7 @@ AAAAU2NhbGVUeXBlAwAAAAQAAABTaXplCgAAAAA8AAAAAAAAADwAAAA=]]> - + 0 -1 - + 0 AAAAAA== @@ -801,7 +803,7 @@ emUKAACAPwAAAAAAAAAAAAAAAA==]]> - + -1 - + 0 - RBX2C62B177C69A499883D8BD697CD45A18 + RBX6DFAD72BC8234139AAAA97B340E0B522 0 false @@ -836,7 +838,7 @@ bmRDb2xvcg/NzMw+zczMPs3MzD4OAAAAVG9vbFRpcFBhZGRpbmcJAAAAAAIAAAA=]]> - + - + -1 - + 0 - RBX0E1020DB074E4CFDB870DC4566DC7B5E + RBX5BC6B7A90E894F219CFECAEDA47F0982 0 false From 7371082cf2338183229cea2d20f66d734ad12495 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 14 Mar 2026 01:07:31 -0700 Subject: [PATCH 082/186] Add opening backpack Signed-off-by: Ryan Luu --- src/Components/Backpack.luau | 6 ++++-- src/Components/Inventory.luau | 2 ++ src/Stories/Backpack.story.luau | 1 + src/Stories/Inventory.story.luau | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Components/Backpack.luau b/src/Components/Backpack.luau index be05a9df..10db563c 100644 --- a/src/Components/Backpack.luau +++ b/src/Components/Backpack.luau @@ -2,10 +2,11 @@ local React = require(script.Parent.Parent.Parent.react) -local Inventory = require(script.Parent.Inventory) local Hotbar = require(script.Parent.Hotbar) +local Inventory = require(script.Parent.Inventory) export type Props = { + size: UDim2?, forceGamepadHintVisible: boolean?, forceKeyboardHintVisible: boolean?, slots: number?, @@ -15,6 +16,7 @@ export type Props = { local function Backpack(props: Props) return React.createElement("Frame", { + Size = props.size, [React.Tag] = "Backpack", }, { Hotbar = React.createElement(Hotbar, { @@ -29,7 +31,7 @@ local function Backpack(props: Props) forceKeyboardHintVisible = props.forceKeyboardHintVisible, slots = props.slots, tools = props.tools, - opened = props.opened, + visible = props.opened, }), }) end diff --git a/src/Components/Inventory.luau b/src/Components/Inventory.luau index b3743032..75a621d0 100644 --- a/src/Components/Inventory.luau +++ b/src/Components/Inventory.luau @@ -15,6 +15,7 @@ export type Props = { forceHintVisible: boolean?, size: UDim2?, -- TODO: change size to use slots amount tools: { Tool? }?, + visible: boolean?, } local function Inventory(props: Props) @@ -34,6 +35,7 @@ local function Inventory(props: Props) return React.createElement("Frame", { Size = props.size, + Visible = props.visible, [React.Tag] = "Inventory", }, { Hints = React.createElement("Frame", { diff --git a/src/Stories/Backpack.story.luau b/src/Stories/Backpack.story.luau index 4a93b80e..97731ed4 100644 --- a/src/Stories/Backpack.story.luau +++ b/src/Stories/Backpack.story.luau @@ -28,6 +28,7 @@ return { Tool.ToolTip = props.controls.toolTooltip return React.createElement(Backpack, { + size = UDim2.fromOffset(655, 0), forceGamepadHintVisible = props.controls.hintVisible, slots = props.controls.slots, tools = { [props.controls.toolSlot] = Tool }, diff --git a/src/Stories/Inventory.story.luau b/src/Stories/Inventory.story.luau index 1e81e994..0c263e18 100644 --- a/src/Stories/Inventory.story.luau +++ b/src/Stories/Inventory.story.luau @@ -30,7 +30,7 @@ return { return React.createElement(Inventory, { forceHintVisible = props.controls.hintVisible, - size = UDim2.fromOffset(655, 320), + size = UDim2.fromOffset(655, 300), tools = tools, }) end, From 72ad41e2a0d69119ed2bbd397f6b8de9146922f2 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 14 Mar 2026 01:21:02 -0700 Subject: [PATCH 083/186] Allow changing tools between hotbar and inventory Signed-off-by: Ryan Luu --- src/Components/Backpack.luau | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Components/Backpack.luau b/src/Components/Backpack.luau index 10db563c..04a3ec14 100644 --- a/src/Components/Backpack.luau +++ b/src/Components/Backpack.luau @@ -15,6 +15,19 @@ export type Props = { } local function Backpack(props: Props) + -- Negative index for inventory and positive index for hotbar + local hotbarTools: { [number]: Tool? } = {} + local inventoryTools: { [number]: Tool? } = {} + if props.tools then + for index, tool in props.tools do + if tool and index > 0 then + hotbarTools[index] = tool + elseif tool and index < 0 then + inventoryTools[math.abs(index)] = tool + end + end + end + return React.createElement("Frame", { Size = props.size, [React.Tag] = "Backpack", @@ -23,14 +36,14 @@ local function Backpack(props: Props) forceGamepadHintVisible = props.forceGamepadHintVisible, forceKeyboardHintVisible = props.forceKeyboardHintVisible, slots = props.slots, - tools = props.tools, + tools = hotbarTools, opened = props.opened, }), Inventory = React.createElement(Inventory, { forceGamepadHintVisible = props.forceGamepadHintVisible, forceKeyboardHintVisible = props.forceKeyboardHintVisible, slots = props.slots, - tools = props.tools, + tools = inventoryTools, visible = props.opened, }), }) From 732596b98438f11633f8f4285c9e41c373fe38ff Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 15 Mar 2026 01:11:54 -0700 Subject: [PATCH 084/186] Add logic for click equipping Signed-off-by: Ryan Luu --- src/Components/Slot.luau | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Components/Slot.luau b/src/Components/Slot.luau index e784d096..efd738d2 100644 --- a/src/Components/Slot.luau +++ b/src/Components/Slot.luau @@ -12,7 +12,6 @@ export type Props = { unlocked: boolean?, forceHintVisible: boolean?, order: number?, - onActivated: (() -> ())?, } local function Slot(props: Props) @@ -21,6 +20,8 @@ local function Slot(props: Props) local toolImage = tool and tool.TextureId local tooltipText = tool and tool.ToolTip + local equipped, setEquipped = React.useState(props.equipped or false) + -- Only show numbers 1-10 for hints and show 0 for the 10th slot local order = props.order or 1 local slotNumber = "" @@ -61,7 +62,7 @@ local function Slot(props: Props) if props.unlocked then tags = tags .. " Unlocked" end - if props.equipped then + if equipped then tags = tags .. " Equipped" end @@ -75,7 +76,9 @@ local function Slot(props: Props) Text = slotText, LayoutOrder = props.order, [React.Tag] = tags, - [React.Event.Activated] = props.onActivated, + [React.Event.Activated] = function() + setEquipped(not equipped) + end, }, { NumberHint = React.createElement("TextLabel", { Text = slotNumber, From 12c4ab349675dd1003893dbf8a2a5e8576db2c47 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 15 Mar 2026 21:23:09 -0700 Subject: [PATCH 085/186] Fix inventory hint Signed-off-by: Ryan Luu --- src/Components/Backpack.luau | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Components/Backpack.luau b/src/Components/Backpack.luau index 04a3ec14..e3a705aa 100644 --- a/src/Components/Backpack.luau +++ b/src/Components/Backpack.luau @@ -40,8 +40,7 @@ local function Backpack(props: Props) opened = props.opened, }), Inventory = React.createElement(Inventory, { - forceGamepadHintVisible = props.forceGamepadHintVisible, - forceKeyboardHintVisible = props.forceKeyboardHintVisible, + forceHintVisible = props.forceGamepadHintVisible, slots = props.slots, tools = inventoryTools, visible = props.opened, From df6ce50e884194e3e86f44a5dc67ca5a2e973267 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 2 Apr 2026 01:40:03 -0700 Subject: [PATCH 086/186] Remove extra property Signed-off-by: Ryan Luu --- src/Bindings/HotbarContext.model.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Bindings/HotbarContext.model.json b/src/Bindings/HotbarContext.model.json index 561d9f10..a70243cb 100644 --- a/src/Bindings/HotbarContext.model.json +++ b/src/Bindings/HotbarContext.model.json @@ -163,9 +163,6 @@ { "Name": "ToggleInventoryAction", "ClassName": "InputAction", - "Properties": { - "Enabled": false - }, "Children": [ { "Name": "KeyBinding", From 0c60c4e57974c86206c059a6813b61de20e5de2e Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 2 Apr 2026 01:49:00 -0700 Subject: [PATCH 087/186] Add missing keys Signed-off-by: Ryan Luu --- src/Components/InventoryHint.luau | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/InventoryHint.luau b/src/Components/InventoryHint.luau index 19714948..da80ceeb 100644 --- a/src/Components/InventoryHint.luau +++ b/src/Components/InventoryHint.luau @@ -43,10 +43,10 @@ local function InventoryHint(props: Props) Visible = visible, [React.Tag] = "InventoryHint", }, { - React.createElement("ImageLabel", { + Image = React.createElement("ImageLabel", { Image = UserInputService:GetImageForKeyCode(props.keyCode), }), - React.createElement("TextLabel", { + Name = React.createElement("TextLabel", { Text = props.text, }), }) From e15cd6489893b6b42dfe41289ec76a1fb0df4a41 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 3 Apr 2026 23:52:59 -0700 Subject: [PATCH 088/186] Add basic client script Signed-off-by: Ryan Luu --- src/Client.client.luau | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/Client.client.luau diff --git a/src/Client.client.luau b/src/Client.client.luau new file mode 100644 index 00000000..d6c284ba --- /dev/null +++ b/src/Client.client.luau @@ -0,0 +1,27 @@ +--!strict + +local Players = game:GetService("Players") + +local React = require(script.Parent.Parent.react) +local ReactRoblox = require(script.Parent.Parent["react-roblox"]) + +local Backpack = require(script.Parent.Components.Backpack) + +local player = Players.LocalPlayer +local playerGui = player:WaitForChild("PlayerGui") + +local handle = Instance.new("ScreenGui") +handle.Name = "SatchelGui" +handle.ResetOnSpawn = false +handle.Parent = playerGui + +local root = ReactRoblox.createRoot(handle) + +local function Satchel() + return React.createElement(Backpack, { + size = UDim2.fromOffset(655, 0), + slots = 10, + }) +end + +root:render(React.createElement(Satchel)) From 3df404dad45661cee933242b9559571030cbf0b0 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 4 Apr 2026 00:10:40 -0700 Subject: [PATCH 089/186] Add style link Signed-off-by: Ryan Luu --- src/Client.client.luau | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Client.client.luau b/src/Client.client.luau index d6c284ba..5878206e 100644 --- a/src/Client.client.luau +++ b/src/Client.client.luau @@ -7,6 +7,8 @@ local ReactRoblox = require(script.Parent.Parent["react-roblox"]) local Backpack = require(script.Parent.Components.Backpack) +local DESIGN_SHEET = script.Parent.Design.SatchelStyleSheet + local player = Players.LocalPlayer local playerGui = player:WaitForChild("PlayerGui") @@ -24,4 +26,9 @@ local function Satchel() }) end -root:render(React.createElement(Satchel)) +root:render(React.createElement(React.Fragment, nil, { + StyleLink = React.createElement("StyleLink", { + StyleSheet = DESIGN_SHEET, + }), + App = React.createElement(Satchel), +})) From 933f923216f17f67acc71ef8ce2cdb3ed992d1b2 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 4 Apr 2026 00:12:45 -0700 Subject: [PATCH 090/186] Add default props Signed-off-by: Ryan Luu --- src/Components/Backpack.luau | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Components/Backpack.luau b/src/Components/Backpack.luau index e3a705aa..66f58ab4 100644 --- a/src/Components/Backpack.luau +++ b/src/Components/Backpack.luau @@ -15,6 +15,8 @@ export type Props = { } local function Backpack(props: Props) + local opened = props.opened or false + -- Negative index for inventory and positive index for hotbar local hotbarTools: { [number]: Tool? } = {} local inventoryTools: { [number]: Tool? } = {} @@ -43,7 +45,7 @@ local function Backpack(props: Props) forceHintVisible = props.forceGamepadHintVisible, slots = props.slots, tools = inventoryTools, - visible = props.opened, + visible = opened, }), }) end From 49ffb478ffd49cb57779730883ddacd00007187a Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 4 Apr 2026 00:18:51 -0700 Subject: [PATCH 091/186] Disable effect on unmounted Signed-off-by: Ryan Luu --- src/Components/HotbarHint.luau | 2 +- src/Components/InventoryHint.luau | 2 +- src/Components/Slot.luau | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Components/HotbarHint.luau b/src/Components/HotbarHint.luau index c456ff74..edf99b97 100644 --- a/src/Components/HotbarHint.luau +++ b/src/Components/HotbarHint.luau @@ -26,7 +26,7 @@ local function HotbarHint(props: Props) end end - preferredInputChanged() + -- preferredInputChanged() local signal: RBXScriptConnection = UserInputService:GetPropertyChangedSignal("PreferredInput") :Connect(preferredInputChanged) diff --git a/src/Components/InventoryHint.luau b/src/Components/InventoryHint.luau index da80ceeb..47d108f7 100644 --- a/src/Components/InventoryHint.luau +++ b/src/Components/InventoryHint.luau @@ -27,7 +27,7 @@ local function InventoryHint(props: Props) end end - preferredInputChanged() + -- preferredInputChanged() local signal: RBXScriptConnection = UserInputService:GetPropertyChangedSignal("PreferredInput") :Connect(preferredInputChanged) diff --git a/src/Components/Slot.luau b/src/Components/Slot.luau index b7c80808..dbc1142e 100644 --- a/src/Components/Slot.luau +++ b/src/Components/Slot.luau @@ -47,7 +47,7 @@ local function Slot(props: Props) end end - preferredInputChanged() + -- preferredInputChanged() local signal: RBXScriptConnection = UserInputService:GetPropertyChangedSignal("PreferredInput") :Connect(preferredInputChanged) From dfcabdd4b698e62846a10140b292234a9a78e993 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 5 Apr 2026 16:16:19 -0700 Subject: [PATCH 092/186] Fix record Signed-off-by: Ryan Luu --- src/Api/getTopbarIcon.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Api/getTopbarIcon.luau b/src/Api/getTopbarIcon.luau index d4dedf51..56ff2e3d 100644 --- a/src/Api/getTopbarIcon.luau +++ b/src/Api/getTopbarIcon.luau @@ -2,7 +2,7 @@ local RunService = game:GetService("RunService") -local TopbarPlus = require("../../topbarplus") +local TopbarPlus = require(script.Parent.Parent.Parent.topbarplus) local function getTopbarIcon(): TopbarPlus.Icon assert(RunService:IsClient(), "getTopbarIcon can only be called on the client") From 3b624f226944eb9fa5d6b1efb0c339fc2cbc1d6b Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 5 Apr 2026 16:20:20 -0700 Subject: [PATCH 093/186] Ignore dist path Signed-off-by: Ryan Luu --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f3cc969f..00367eb5 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,4 @@ DevPackages/ site/ # Builds -builds/ \ No newline at end of file +dist/ \ No newline at end of file From 13ae35d8763473507234fec154c56e7e30df8f3e Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 5 Apr 2026 16:26:33 -0700 Subject: [PATCH 094/186] Package as standalone Signed-off-by: Ryan Luu --- models/Satchel/Packages.project.json | 2 +- package.project.json | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/models/Satchel/Packages.project.json b/models/Satchel/Packages.project.json index 59b65a7c..52d5154f 100644 --- a/models/Satchel/Packages.project.json +++ b/models/Satchel/Packages.project.json @@ -3,7 +3,7 @@ "tree": { "$path": "../../Packages", "satchel": { - "$path": "../../src" + "$path": "../../default.project.json" } } } \ No newline at end of file diff --git a/package.project.json b/package.project.json index e1778089..bd882b22 100644 --- a/package.project.json +++ b/package.project.json @@ -2,6 +2,9 @@ "name": "Satchel", "emitLegacyScripts": false, "tree": { - "$path": "models" + "$path": "models/Satchel", + "ThumbnailCamera": { + "$path": "models/ThumbnailCamera.model.json" + } } } \ No newline at end of file From f8e7a974b97b6bd0e1f2d81bdea9672441e2746d Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 5 Apr 2026 16:43:26 -0700 Subject: [PATCH 095/186] Add warning for outdated versions Signed-off-by: Ryan Luu --- src/Attribution.client.luau | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Attribution.client.luau b/src/Attribution.client.luau index a3e7ef45..296bc68b 100644 --- a/src/Attribution.client.luau +++ b/src/Attribution.client.luau @@ -18,8 +18,29 @@ Thank you for supporting Satchel. ]] +local MarketplaceService = game:GetService("MarketplaceService") local RunService = game:GetService("RunService") +local VERSION = "2.0.0" + +-- Print attribution. Do not modify without reading above if not RunService:IsStudio() then - print("💼 Running Satchel v1.4.1 by @WinnersTakesAll") + print(`💼 Running Satchel v{VERSION} by @WinnersTakesAll`) +end + +-- Check for updates. You may modify the below +local latestVersion: string? + +local success, result = pcall(function() + return MarketplaceService:GetProductInfoAsync(13947506401) +end) + +if success then + latestVersion = string.match(result.Name, "v(%d+%.%d+%.%d+)") +end + +if latestVersion and latestVersion ~= VERSION then + warn( + `A new version of Satchel (v{VERSION} -> v{latestVersion}) is available: https://create.roblox.com/store/asset/13947506401` + ) end From fdf5208e3d44a9595812f993648ce79ceae78fc4 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 5 Apr 2026 16:49:56 -0700 Subject: [PATCH 096/186] Rename app Signed-off-by: Ryan Luu --- src/Client.client.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Client.client.luau b/src/Client.client.luau index 5878206e..58071904 100644 --- a/src/Client.client.luau +++ b/src/Client.client.luau @@ -30,5 +30,5 @@ root:render(React.createElement(React.Fragment, nil, { StyleLink = React.createElement("StyleLink", { StyleSheet = DESIGN_SHEET, }), - App = React.createElement(Satchel), + Satchel = React.createElement(Satchel), })) From ded3d89b1725026807cd9403971b0702e79accd2 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 5 Apr 2026 17:03:51 -0700 Subject: [PATCH 097/186] Hook topbar icon to opening Signed-off-by: Ryan Luu --- src/TopbarIcon.client.luau | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/TopbarIcon.client.luau b/src/TopbarIcon.client.luau index ff83ee71..a086f6b6 100644 --- a/src/TopbarIcon.client.luau +++ b/src/TopbarIcon.client.luau @@ -1,5 +1,6 @@ --!strict +local Satchel = require(script.Parent) local Icon = require(script.Parent.Parent.topbarplus) local icon = Icon.new() @@ -23,8 +24,8 @@ icon:bindToggleKey(Enum.KeyCode.Backquote) icon:autoDeselect(false) icon:setCaption("Inventory") -icon.toggled:Connect(function(_isSelected, fromSource) +icon.toggled:Connect(function(isSelected, fromSource) if fromSource == "User" then - print("Inventory toggled") + Satchel.setEnabled(isSelected) end end) From 07bd3f331e869db4795c998695aefa1836e79fe4 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 5 Apr 2026 17:10:02 -0700 Subject: [PATCH 098/186] Disable CoreGui backpack Signed-off-by: Ryan Luu --- src/Client.client.luau | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Client.client.luau b/src/Client.client.luau index 58071904..4dc60f4f 100644 --- a/src/Client.client.luau +++ b/src/Client.client.luau @@ -1,6 +1,7 @@ --!strict local Players = game:GetService("Players") +local StarterGui = game:GetService("StarterGui") local React = require(script.Parent.Parent.react) local ReactRoblox = require(script.Parent.Parent["react-roblox"]) @@ -12,6 +13,8 @@ local DESIGN_SHEET = script.Parent.Design.SatchelStyleSheet local player = Players.LocalPlayer local playerGui = player:WaitForChild("PlayerGui") +StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false) + local handle = Instance.new("ScreenGui") handle.Name = "SatchelGui" handle.ResetOnSpawn = false From 09574c89eec798c24accb36ab46074c2ee3e7a3f Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 5 Apr 2026 17:17:09 -0700 Subject: [PATCH 099/186] Add logic for opening inventory Signed-off-by: Ryan Luu --- src/Api/setEnabled.luau | 12 +++++++++++- src/Client.client.luau | 20 ++++++++++++++++++++ src/TopbarIcon.client.luau | 2 +- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/Api/setEnabled.luau b/src/Api/setEnabled.luau index 0142f385..dc205f7e 100644 --- a/src/Api/setEnabled.luau +++ b/src/Api/setEnabled.luau @@ -1,7 +1,17 @@ --!strict +local RunService = game:GetService("RunService") + +local bindableEvents = script.Parent.Parent.BindableEvents + local function setEnabled(isEnabled: boolean) - print("Not implemented") + assert(RunService:IsClient(), "setEnabled can only be called on the client") + + if isEnabled then + bindableEvents.InventoryOpened:Fire() + else + bindableEvents.InventoryClosed:Fire() + end end return setEnabled diff --git a/src/Client.client.luau b/src/Client.client.luau index 4dc60f4f..862256e8 100644 --- a/src/Client.client.luau +++ b/src/Client.client.luau @@ -23,9 +23,29 @@ handle.Parent = playerGui local root = ReactRoblox.createRoot(handle) local function Satchel() + -- Open and close backpack based on bindable events + local opened, setOpened = React.useState(false) + + React.useEffect(function() + local bindableEvents = script.Parent.BindableEvents + + local inventoryOpened = bindableEvents.InventoryOpened.Event:Connect(function() + setOpened(true) + end) + local inventoryClosed = bindableEvents.InventoryClosed.Event:Connect(function() + setOpened(false) + end) + + return function() + inventoryOpened:Disconnect() + inventoryClosed:Disconnect() + end + end, {}) + return React.createElement(Backpack, { size = UDim2.fromOffset(655, 0), slots = 10, + opened = opened, }) end diff --git a/src/TopbarIcon.client.luau b/src/TopbarIcon.client.luau index a086f6b6..e7c13944 100644 --- a/src/TopbarIcon.client.luau +++ b/src/TopbarIcon.client.luau @@ -1,7 +1,7 @@ --!strict -local Satchel = require(script.Parent) local Icon = require(script.Parent.Parent.topbarplus) +local Satchel = require(script.Parent) local icon = Icon.new() icon:modifyTheme({ "IconLabelContainer", "TargetWidth", 0 }) -- Force minimum width From 6cfa7ecec2effb35c437bb1033366a5e500017ff Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 5 Apr 2026 18:35:54 -0700 Subject: [PATCH 100/186] Fix using wrong API Signed-off-by: Ryan Luu --- src/Api/closeInventory.luau | 5 ++++- src/Api/openInventory.luau | 5 ++++- src/Api/setEnabled.luau | 8 -------- src/TopbarIcon.client.luau | 6 +++++- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/Api/closeInventory.luau b/src/Api/closeInventory.luau index 8bc9855a..4bfdb5a7 100644 --- a/src/Api/closeInventory.luau +++ b/src/Api/closeInventory.luau @@ -2,9 +2,12 @@ local RunService = game:GetService("RunService") +local bindableEvents = script.Parent.Parent.BindableEvents + local function closeInventory() assert(RunService:IsClient(), "closeInventory can only be called on the client") - print("Not implemented") + + bindableEvents.InventoryClosed:Fire() end return closeInventory diff --git a/src/Api/openInventory.luau b/src/Api/openInventory.luau index 8ab5e386..d9723363 100644 --- a/src/Api/openInventory.luau +++ b/src/Api/openInventory.luau @@ -2,9 +2,12 @@ local RunService = game:GetService("RunService") +local bindableEvents = script.Parent.Parent.BindableEvents + local function openInventory() assert(RunService:IsClient(), "openInventory can only be called on the client") - print("Not implemented") + + bindableEvents.InventoryOpened:Fire() end return openInventory diff --git a/src/Api/setEnabled.luau b/src/Api/setEnabled.luau index dc205f7e..1eab95de 100644 --- a/src/Api/setEnabled.luau +++ b/src/Api/setEnabled.luau @@ -2,16 +2,8 @@ local RunService = game:GetService("RunService") -local bindableEvents = script.Parent.Parent.BindableEvents - local function setEnabled(isEnabled: boolean) assert(RunService:IsClient(), "setEnabled can only be called on the client") - - if isEnabled then - bindableEvents.InventoryOpened:Fire() - else - bindableEvents.InventoryClosed:Fire() - end end return setEnabled diff --git a/src/TopbarIcon.client.luau b/src/TopbarIcon.client.luau index e7c13944..74d66bc7 100644 --- a/src/TopbarIcon.client.luau +++ b/src/TopbarIcon.client.luau @@ -26,6 +26,10 @@ icon:setCaption("Inventory") icon.toggled:Connect(function(isSelected, fromSource) if fromSource == "User" then - Satchel.setEnabled(isSelected) + if isSelected then + Satchel.openInventory() + else + Satchel.closeInventory() + end end end) From b5b81cd3467b577ee252057006e06b6c2a1b8f2f Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 5 Apr 2026 18:39:21 -0700 Subject: [PATCH 101/186] Add signal suffix Signed-off-by: Ryan Luu --- src/Client.client.luau | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Client.client.luau b/src/Client.client.luau index 862256e8..cae67bfe 100644 --- a/src/Client.client.luau +++ b/src/Client.client.luau @@ -29,16 +29,16 @@ local function Satchel() React.useEffect(function() local bindableEvents = script.Parent.BindableEvents - local inventoryOpened = bindableEvents.InventoryOpened.Event:Connect(function() + local inventoryOpenedSignal = bindableEvents.InventoryOpened.Event:Connect(function() setOpened(true) end) - local inventoryClosed = bindableEvents.InventoryClosed.Event:Connect(function() + local inventoryClosedSignal = bindableEvents.InventoryClosed.Event:Connect(function() setOpened(false) end) return function() - inventoryOpened:Disconnect() - inventoryClosed:Disconnect() + inventoryOpenedSignal:Disconnect() + inventoryClosedSignal:Disconnect() end end, {}) From bb9f569aa1442c89e24db75ad93ea7d30e36c0c7 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 5 Apr 2026 18:49:44 -0700 Subject: [PATCH 102/186] Add basic enabled API Signed-off-by: Ryan Luu --- src/Api/setEnabled.luau | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Api/setEnabled.luau b/src/Api/setEnabled.luau index 1eab95de..cd0c15b0 100644 --- a/src/Api/setEnabled.luau +++ b/src/Api/setEnabled.luau @@ -1,9 +1,18 @@ --!strict +local Players = game:GetService("Players") local RunService = game:GetService("RunService") +local player = Players.LocalPlayer +local playerGui = player:WaitForChild("PlayerGui") +local screenGui = playerGui:WaitForChild("SatchelGui") + local function setEnabled(isEnabled: boolean) assert(RunService:IsClient(), "setEnabled can only be called on the client") + + screenGui.Enabled = isEnabled + + -- TODO: Disable topbar icon end return setEnabled From 1610521743c8196c5e94e05d4d13ee2d72488ebd Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 5 Apr 2026 19:02:31 -0700 Subject: [PATCH 103/186] Add test scripts Signed-off-by: Ryan Luu --- test.project.json | 15 +++++++++++++++ tests/ToggleCoreGui.client.luau | 13 +++++++++++++ tests/ToggleSatchel.client.luau | 12 ++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 test.project.json create mode 100644 tests/ToggleCoreGui.client.luau create mode 100644 tests/ToggleSatchel.client.luau diff --git a/test.project.json b/test.project.json new file mode 100644 index 00000000..32cff523 --- /dev/null +++ b/test.project.json @@ -0,0 +1,15 @@ +{ + "name": "Test Satchel", + "emitLegacyScripts": false, + "tree": { + "$className": "DataModel", + "ReplicatedStorage": { + "$className": "ReplicatedStorage", + "$ignoreUnknownInstances": true, + "$path": "tests", + "Satchel": { + "$path": "models/Satchel" + } + } + } +} \ No newline at end of file diff --git a/tests/ToggleCoreGui.client.luau b/tests/ToggleCoreGui.client.luau new file mode 100644 index 00000000..9cac6f9b --- /dev/null +++ b/tests/ToggleCoreGui.client.luau @@ -0,0 +1,13 @@ +--!strict + +local StarterGui = game:GetService("StarterGui") + +local Icon = require(script.Parent.Satchel.Packages.topbarplus) + +local icon = Icon.new() +icon:setLabel("Toggle CoreGui Backpack") +icon:align("Right") +icon:bindEvent("deselected", function() + StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, not StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Backpack)) +end) +icon:oneClick() diff --git a/tests/ToggleSatchel.client.luau b/tests/ToggleSatchel.client.luau new file mode 100644 index 00000000..f4046dd1 --- /dev/null +++ b/tests/ToggleSatchel.client.luau @@ -0,0 +1,12 @@ +--!strict + +local Icon = require(script.Parent.Satchel.Packages.topbarplus) +local Satchel = require(script.Parent.Satchel) + +local icon = Icon.new() +icon:setLabel("Toggle Satchel") +icon:align("Right") +icon:bindEvent("deselected", function() + Satchel.setEnabled(not Satchel.getEnabled()) +end) +icon:oneClick() From 0dbbd5cc62144097a7f260eac3d681bb2cafb5e8 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 5 Apr 2026 19:16:33 -0700 Subject: [PATCH 104/186] Add logic for toggling inventory Signed-off-by: Ryan Luu --- src/Api/getEnabled.luau | 16 ++++++++++++++++ src/Api/getTopbarIcon.luau | 10 ++++++++-- src/Api/setEnabled.luau | 7 ++++++- src/init.luau | 1 + 4 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 src/Api/getEnabled.luau diff --git a/src/Api/getEnabled.luau b/src/Api/getEnabled.luau new file mode 100644 index 00000000..0e4a35da --- /dev/null +++ b/src/Api/getEnabled.luau @@ -0,0 +1,16 @@ +--!strict + +local Players = game:GetService("Players") +local RunService = game:GetService("RunService") + +local player = Players.LocalPlayer +local playerGui = player:WaitForChild("PlayerGui") +local screenGui = playerGui:WaitForChild("SatchelGui") + +local function getEnabled() + assert(RunService:IsClient(), "getEnabled can only be called on the client") + + return screenGui.Enabled +end + +return getEnabled diff --git a/src/Api/getTopbarIcon.luau b/src/Api/getTopbarIcon.luau index 56ff2e3d..69122d6e 100644 --- a/src/Api/getTopbarIcon.luau +++ b/src/Api/getTopbarIcon.luau @@ -4,9 +4,15 @@ local RunService = game:GetService("RunService") local TopbarPlus = require(script.Parent.Parent.Parent.topbarplus) -local function getTopbarIcon(): TopbarPlus.Icon +local function getTopbarIcon(): TopbarPlus.Icon? assert(RunService:IsClient(), "getTopbarIcon can only be called on the client") - print("Not implemented") + + for _, icon in TopbarPlus.getIcons() do + if icon.captionText == "Inventory" then + return icon + end + end + return nil end diff --git a/src/Api/setEnabled.luau b/src/Api/setEnabled.luau index cd0c15b0..ab623395 100644 --- a/src/Api/setEnabled.luau +++ b/src/Api/setEnabled.luau @@ -3,6 +3,8 @@ local Players = game:GetService("Players") local RunService = game:GetService("RunService") +local getTopbarIcon = require(script.Parent.getTopbarIcon) + local player = Players.LocalPlayer local playerGui = player:WaitForChild("PlayerGui") local screenGui = playerGui:WaitForChild("SatchelGui") @@ -12,7 +14,10 @@ local function setEnabled(isEnabled: boolean) screenGui.Enabled = isEnabled - -- TODO: Disable topbar icon + local icon = getTopbarIcon() + if icon then + icon:setEnabled(isEnabled) + end end return setEnabled diff --git a/src/init.luau b/src/init.luau index 3dc68d84..d89cb384 100644 --- a/src/init.luau +++ b/src/init.luau @@ -4,6 +4,7 @@ local bindableEvents = script.BindableEvents return { -- Functions + getEnabled = require(script.Api.getEnabled), setEnabled = require(script.Api.setEnabled), getTopbarIcon = require(script.Api.getTopbarIcon), openInventory = require(script.Api.openInventory), From 5a2fed99bd111d008863e65b47fa9c31d3449aff Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 5 Apr 2026 19:19:19 -0700 Subject: [PATCH 105/186] Add logic for detecting state Signed-off-by: Ryan Luu --- src/Api/isInventoryOpen.luau | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Api/isInventoryOpen.luau b/src/Api/isInventoryOpen.luau index b18b9cb8..42e8eb2b 100644 --- a/src/Api/isInventoryOpen.luau +++ b/src/Api/isInventoryOpen.luau @@ -2,9 +2,22 @@ local RunService = game:GetService("RunService") +local bindableEvents = script.Parent.Parent.BindableEvents + +local inventoryOpen = false + +bindableEvents.InventoryOpened.Event:Connect(function() + inventoryOpen = true +end) + +bindableEvents.InventoryClosed.Event:Connect(function() + inventoryOpen = false +end) + local function isInventoryOpen(): boolean assert(RunService:IsClient(), "isInventoryOpen can only be called on the client") - return nil -- Not implemented + + return inventoryOpen end return isInventoryOpen From e799475d81cbbc0d2234d5a514676b8bd1c52cc7 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 5 Apr 2026 19:23:41 -0700 Subject: [PATCH 106/186] Add test for toggling inventory Signed-off-by: Ryan Luu --- src/TopbarIcon.client.luau | 8 ++++++++ tests/ToggleInventory.client.luau | 16 ++++++++++++++++ ...ent.luau => ToggleSatchelEnabled.client.luau} | 0 3 files changed, 24 insertions(+) create mode 100644 tests/ToggleInventory.client.luau rename tests/{ToggleSatchel.client.luau => ToggleSatchelEnabled.client.luau} (100%) diff --git a/src/TopbarIcon.client.luau b/src/TopbarIcon.client.luau index 74d66bc7..513eba46 100644 --- a/src/TopbarIcon.client.luau +++ b/src/TopbarIcon.client.luau @@ -33,3 +33,11 @@ icon.toggled:Connect(function(isSelected, fromSource) end end end) + +Satchel.inventoryOpened:Connect(function() + icon:select() +end) + +Satchel.inventoryClosed:Connect(function() + icon:deselect() +end) diff --git a/tests/ToggleInventory.client.luau b/tests/ToggleInventory.client.luau new file mode 100644 index 00000000..bed2d44c --- /dev/null +++ b/tests/ToggleInventory.client.luau @@ -0,0 +1,16 @@ +--!strict + +local Icon = require(script.Parent.Satchel.Packages.topbarplus) +local Satchel = require(script.Parent.Satchel) + +local icon = Icon.new() +icon:setLabel("Toggle Inventory") +icon:align("Right") +icon:bindEvent("deselected", function() + if Satchel.isInventoryOpen() then + Satchel.closeInventory() + else + Satchel.openInventory() + end +end) +icon:oneClick() diff --git a/tests/ToggleSatchel.client.luau b/tests/ToggleSatchelEnabled.client.luau similarity index 100% rename from tests/ToggleSatchel.client.luau rename to tests/ToggleSatchelEnabled.client.luau From c8e7184b8b5a4ce683beeabafd745a9017f3dcf3 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sun, 5 Apr 2026 19:27:18 -0700 Subject: [PATCH 107/186] Simplify get icon logic Signed-off-by: Ryan Luu --- src/Api/getTopbarIcon.luau | 8 +------- src/TopbarIcon.client.luau | 1 + 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/Api/getTopbarIcon.luau b/src/Api/getTopbarIcon.luau index 69122d6e..1260b8f4 100644 --- a/src/Api/getTopbarIcon.luau +++ b/src/Api/getTopbarIcon.luau @@ -7,13 +7,7 @@ local TopbarPlus = require(script.Parent.Parent.Parent.topbarplus) local function getTopbarIcon(): TopbarPlus.Icon? assert(RunService:IsClient(), "getTopbarIcon can only be called on the client") - for _, icon in TopbarPlus.getIcons() do - if icon.captionText == "Inventory" then - return icon - end - end - - return nil + return TopbarPlus.getIcon("SatchelInventory") end return getTopbarIcon diff --git a/src/TopbarIcon.client.luau b/src/TopbarIcon.client.luau index 513eba46..a8b6c103 100644 --- a/src/TopbarIcon.client.luau +++ b/src/TopbarIcon.client.luau @@ -4,6 +4,7 @@ local Icon = require(script.Parent.Parent.topbarplus) local Satchel = require(script.Parent) local icon = Icon.new() +icon:setName("SatchelInventory") icon:modifyTheme({ "IconLabelContainer", "TargetWidth", 0 }) -- Force minimum width icon:setLabel("backpack") icon:setOrder(-1) From 5dfb4c7140761183eb841830b75093ad428c31d9 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 6 Apr 2026 11:12:57 -0700 Subject: [PATCH 108/186] Rename keycode string Signed-off-by: Ryan Luu --- src/Components/InventoryHint.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/InventoryHint.luau b/src/Components/InventoryHint.luau index 47d108f7..44265103 100644 --- a/src/Components/InventoryHint.luau +++ b/src/Components/InventoryHint.luau @@ -46,7 +46,7 @@ local function InventoryHint(props: Props) Image = React.createElement("ImageLabel", { Image = UserInputService:GetImageForKeyCode(props.keyCode), }), - Name = React.createElement("TextLabel", { + KeyCode = React.createElement("TextLabel", { Text = props.text, }), }) From e6475f05acb83bee1da39f55a73ebfda7befb0b4 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 6 Apr 2026 11:22:00 -0700 Subject: [PATCH 109/186] Dynamically adjust slots Signed-off-by: Ryan Luu --- src/Client.client.luau | 24 +++++++++++++++++++++++- src/Components/HotbarHint.luau | 3 +-- src/Components/InventoryHint.luau | 3 +-- src/Components/Slot.luau | 3 +-- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/Client.client.luau b/src/Client.client.luau index cae67bfe..8062ea39 100644 --- a/src/Client.client.luau +++ b/src/Client.client.luau @@ -1,5 +1,6 @@ --!strict +local GuiService = game:GetService("GuiService") local Players = game:GetService("Players") local StarterGui = game:GetService("StarterGui") @@ -42,9 +43,30 @@ local function Satchel() end end, {}) + -- Change slots based on viewport display size + local slots, setSlots = React.useState(10) + + React.useEffect(function() + local function viewportDisplaySizeChanged() + local viewportSize = GuiService.ViewportDisplaySize + if viewportSize == Enum.DisplaySize.Small then + setSlots(5) + else + setSlots(10) + end + end + + viewportDisplaySizeChanged() + local signal = GuiService:GetPropertyChangedSignal("ViewportDisplaySize"):Connect(viewportDisplaySizeChanged) + + return function() + signal:Disconnect() + end + end, {}) + return React.createElement(Backpack, { size = UDim2.fromOffset(655, 0), - slots = 10, + slots = slots, opened = opened, }) end diff --git a/src/Components/HotbarHint.luau b/src/Components/HotbarHint.luau index edf99b97..861006e4 100644 --- a/src/Components/HotbarHint.luau +++ b/src/Components/HotbarHint.luau @@ -27,8 +27,7 @@ local function HotbarHint(props: Props) end -- preferredInputChanged() - local signal: RBXScriptConnection = UserInputService:GetPropertyChangedSignal("PreferredInput") - :Connect(preferredInputChanged) + local signal = UserInputService:GetPropertyChangedSignal("PreferredInput"):Connect(preferredInputChanged) return function() signal:Disconnect() diff --git a/src/Components/InventoryHint.luau b/src/Components/InventoryHint.luau index 44265103..c9c9e24c 100644 --- a/src/Components/InventoryHint.luau +++ b/src/Components/InventoryHint.luau @@ -28,8 +28,7 @@ local function InventoryHint(props: Props) end -- preferredInputChanged() - local signal: RBXScriptConnection = UserInputService:GetPropertyChangedSignal("PreferredInput") - :Connect(preferredInputChanged) + local signal = UserInputService:GetPropertyChangedSignal("PreferredInput"):Connect(preferredInputChanged) return function() signal:Disconnect() diff --git a/src/Components/Slot.luau b/src/Components/Slot.luau index dbc1142e..1d0b62a7 100644 --- a/src/Components/Slot.luau +++ b/src/Components/Slot.luau @@ -48,8 +48,7 @@ local function Slot(props: Props) end -- preferredInputChanged() - local signal: RBXScriptConnection = UserInputService:GetPropertyChangedSignal("PreferredInput") - :Connect(preferredInputChanged) + local signal = UserInputService:GetPropertyChangedSignal("PreferredInput"):Connect(preferredInputChanged) return function() signal:Disconnect() From e0a4fba2b68733cf7398e6f944f4606d117a5ce2 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 6 Apr 2026 11:42:02 -0700 Subject: [PATCH 110/186] Automatically resize based on slots Hint slots cause resize but this will be fixed later on Signed-off-by: Ryan Luu --- src/Client.client.luau | 1 - src/Components/Backpack.luau | 2 - src/Design.rbxmx | 974 +++++++++++++++++------------------ 3 files changed, 487 insertions(+), 490 deletions(-) diff --git a/src/Client.client.luau b/src/Client.client.luau index 8062ea39..968680bb 100644 --- a/src/Client.client.luau +++ b/src/Client.client.luau @@ -65,7 +65,6 @@ local function Satchel() end, {}) return React.createElement(Backpack, { - size = UDim2.fromOffset(655, 0), slots = slots, opened = opened, }) diff --git a/src/Components/Backpack.luau b/src/Components/Backpack.luau index 66f58ab4..2f63dcba 100644 --- a/src/Components/Backpack.luau +++ b/src/Components/Backpack.luau @@ -6,7 +6,6 @@ local Hotbar = require(script.Parent.Hotbar) local Inventory = require(script.Parent.Inventory) export type Props = { - size: UDim2?, forceGamepadHintVisible: boolean?, forceKeyboardHintVisible: boolean?, slots: number?, @@ -31,7 +30,6 @@ local function Backpack(props: Props) end return React.createElement("Frame", { - Size = props.size, [React.Tag] = "Backpack", }, { Hotbar = React.createElement(Hotbar, { diff --git a/src/Design.rbxmx b/src/Design.rbxmx index 19b96c85..272c3607 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,152 +11,208 @@ -1 - + - AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= + 0 false - DefaultTheme + BaseTokens -1 - + 0 - RBX6DFAD72BC8234139AAAA97B340E0B522 + RBXE0F93419279746199C322A065DD297C3 0 false - Derive from BaseTokens + Derive from ThemeTokens -1 - + - + 0 false - SatchelStyleSheet + ThemeTokens + -1 + + + + + + + 0 + false + LegacyTheme -1 - + 0 - - - .Hints + RBX318BFD9CE35E4CD8848DAD895F5A8213 0 false - .Hints + Derive from BaseTokens -1 - - - 0 - - - ::UIListLayout - - 0 - false - ::UIListLayout - -1 - - - - + + + + + 0 + false + SatchelStyleSheet + -1 + + + 0 - + - TextLabel.Tooltip + TextBox.Searchbar 0 false - TextLabel.Tooltip + TextBox.Searchbar -1 - + 0 - + AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= - ::UIPadding + ::UICorner 0 false - ::UIPadding + ::UICorner -1 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz + - ::UICorner + >ImageButton 0 false - ::UICorner + >ImageButton -1 + + + 0 + AAAAAA== + + ::UIAspectRatioConstraint + + 0 + false + ::UIAspectRatioConstraint + -1 + + + - - - - 0 - - - .Hotbar - - 0 - false - .Hotbar - -1 - - - + 0 - + - ::UIListLayout + ::UIStroke 0 false - ::UIListLayout + ::UIStroke -1 - + 0 - AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= + ::UIPadding @@ -168,204 +224,151 @@ aWdubWVudBURAAAAVmVydGljYWxBbGlnbm1lbnQAAAAA]]> - + 0 - + - .InventoryHint + .HotbarHint 0 false - .InventoryHint + .HotbarHint -1 - + 0 - + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== - >ImageLabel + ::UIAspectRatioConstraint 0 false - >ImageLabel + ::UIAspectRatioConstraint -1 - - - 0 - AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - + + + + 0 + + + .Hints + + 0 + false + .Hints + -1 + + + 0 - + - >TextLabel + ::UIListLayout 0 false - >TextLabel + ::UIListLayout -1 - + 0 - + - TextBox.Searchbar + .Inventory 0 false - TextBox.Searchbar + .Inventory -1 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= + AAAAAA== - ::UICorner + ::UIListLayout 0 false - ::UICorner + ::UIListLayout -1 - - - 0 - - - ::UIPadding - - 0 - false - ::UIPadding - -1 - - - - - - 0 - - - ::UIStroke - - 0 - false - ::UIStroke - -1 - - - - - - 0 - - - >ImageButton - - 0 - false - >ImageButton - -1 - - - - - 0 - AAAAAA== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - - + 0 - + - .Slots + .Backpack 0 false - .Slots + .Backpack -1 - + 0 - + - ::UIPadding + ::UIListLayout 0 false - ::UIPadding + ::UIListLayout -1 - + + + + 0 + + + TextLabel.Tooltip + + 0 + false + TextLabel.Tooltip + -1 + + + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz ::UICorner @@ -376,77 +379,69 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkU3VyZmFjZVBhZGRpbmc=]]> - - - 0 - AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA - - ::UIListLayout - - 0 - false - ::UIListLayout - -1 - - - - + 0 - + - >ScrollingFrame + ::UIPadding 0 false - >ScrollingFrame + ::UIPadding -1 - - - 0 - - - ::UIListLayout - - 0 - false - ::UIListLayout - -1 - - - - + 0 - + RBX9A9FAF7F89E64E39A8717BD548CA0A5D + + 0 + false + Derive from DefaultTheme + -1 + + + + + + 0 + - .Backpack + .Hotbar 0 false - .Backpack + .Hotbar -1 - + 0 - + AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + + + + 0 + ::UIListLayout @@ -458,7 +453,7 @@ EQAAAFZlcnRpY2FsQWxpZ25tZW50AgAAAA==]]> - + 0 -1 - - - 0 - - - ::UIPadding - - 0 - false - ::UIPadding - -1 - - - - + 0 - + AAAAAA== - ::UITextSizeConstraint + .Equipped 0 false - ::UITextSizeConstraint + .Equipped -1 + + + 0 + + + ::UIStroke + + 0 + false + ::UIStroke + -1 + + + - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz + - ::UICorner + ::UIPadding 0 false - ::UICorner + ::UIPadding -1 - + 0 - AAAAAA== + - :Press + .Unlocked 0 false - :Press + .Unlocked -1 - + 0 - AQAAAAcAAABWaXNpYmxlAwE= + AAAAAA== - >.Tooltip + :Press 0 false - >.Tooltip + :Press -1 + + + 0 + + + ::UIStroke + + 0 + false + ::UIStroke + -1 + + + - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== @@ -579,218 +592,176 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> - + 0 - AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= + AAAAAA== - >TextLabel + :Hover 0 false - >TextLabel + :Hover -1 - + 0 - AQAAAAcAAABWaXNpYmxlAwA= - - .Tooltip - - 0 - false - .Tooltip - -1 - - - - - - 0 - + AQAAAAcAAABWaXNpYmxlAwE= - .SlotNumber + >.Tooltip 0 false - .SlotNumber + >.Tooltip -1 - + 0 - + AAAAAA== - .Unlocked + :Press 0 false - .Unlocked + :Press -1 - + 0 - AAAAAA== + AQAAAAcAAABWaXNpYmxlAwE= - :Press + >.Tooltip 0 false - :Press + >.Tooltip -1 - - - 0 - - - ::UIStroke - - 0 - false - ::UIStroke - -1 - - - - + 0 - AAAAAA== + AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= - .Equipped + >TextLabel 0 false - .Equipped + >TextLabel -1 - + 0 - + - ::UIStroke + .SlotNumber 0 false - ::UIStroke + .SlotNumber -1 - - - - 0 - AAAAAA== - - :Hover - - 0 - false - :Hover - -1 - - - + 0 - AQAAAAcAAABWaXNpYmxlAwE= + AQAAAAcAAABWaXNpYmxlAwA= - >.Tooltip + .Tooltip 0 false - >.Tooltip + .Tooltip -1 - - - - 0 - - - .HotbarHint - - 0 - false - .HotbarHint - -1 - - - + 0 - AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== + - ::UIAspectRatioConstraint + ::UITextSizeConstraint 0 false - ::UIAspectRatioConstraint + ::UITextSizeConstraint + -1 + + + + + + 0 + AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz + + ::UICorner + + 0 + false + ::UICorner -1 - - - 0 - RBX39C4CD6CC7364378BD7D7EC698DF3F46 - - 0 - false - Derive from DefaultTheme - -1 - - - - + 0 - + - .Inventory + .Slots 0 false - .Inventory + .Slots -1 - + 0 - AAAAAA== + + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + + + + 0 + AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA ::UIListLayout @@ -801,108 +772,137 @@ emUKAACAPwAAAAAAAAAAAAAAAA==]]> + + + 0 + + + >ScrollingFrame + + 0 + false + >ScrollingFrame + -1 + + + + + 0 + + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + + + + + 0 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz + + ::UICorner + + 0 + false + ::UICorner + -1 + + + - - - - - 0 - false - LegacyTheme - -1 - - - + 0 - RBX6DFAD72BC8234139AAAA97B340E0B522 + + + .InventoryHint 0 false - Derive from BaseTokens + .InventoryHint -1 + + + 0 + + + >ImageLabel + + 0 + false + >ImageLabel + -1 + + + + + 0 + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== + + ::UIAspectRatioConstraint + + 0 + false + ::UIAspectRatioConstraint + -1 + + + + + + + 0 + + + >TextLabel + + 0 + false + >TextLabel + -1 + + + - - - - 0 - false - ThemeTokens - -1 - - - - + - + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= 0 false - BaseTokens + DefaultTheme -1 - + 0 - RBX5BC6B7A90E894F219CFECAEDA47F0982 + RBX318BFD9CE35E4CD8848DAD895F5A8213 0 false - Derive from ThemeTokens + Derive from BaseTokens -1 From d77ab27129588ff9f7719b2428ea0a0b9459e14c Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 6 Apr 2026 11:45:27 -0700 Subject: [PATCH 111/186] Remove old size prop Signed-off-by: Ryan Luu --- src/Stories/Backpack.story.luau | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Stories/Backpack.story.luau b/src/Stories/Backpack.story.luau index 97731ed4..4a93b80e 100644 --- a/src/Stories/Backpack.story.luau +++ b/src/Stories/Backpack.story.luau @@ -28,7 +28,6 @@ return { Tool.ToolTip = props.controls.toolTooltip return React.createElement(Backpack, { - size = UDim2.fromOffset(655, 0), forceGamepadHintVisible = props.controls.hintVisible, slots = props.controls.slots, tools = { [props.controls.toolSlot] = Tool }, From 8788865bb42e4c1eb0771326ef9d1be1f95aa1fd Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 6 Apr 2026 12:04:43 -0700 Subject: [PATCH 112/186] Remove gamepad hints from components Signed-off-by: Ryan Luu --- src/Components/Hotbar.luau | 19 - src/Components/Inventory.luau | 35 +- src/Design.rbxmx | 844 ++++++++++++++++------------------ 3 files changed, 409 insertions(+), 489 deletions(-) diff --git a/src/Components/Hotbar.luau b/src/Components/Hotbar.luau index dca09b83..f580b18d 100644 --- a/src/Components/Hotbar.luau +++ b/src/Components/Hotbar.luau @@ -2,13 +2,8 @@ local React = require(script.Parent.Parent.Parent.react) -local HotbarHint = require(script.Parent.HotbarHint) local Slot = require(script.Parent.Slot) -local HotbarBindings = script.Parent.Parent.Bindings.HotbarContext -local SlotLeftGamepadKeyCode = HotbarBindings.SlotLeftAction.GamepadBinding.KeyCode -local SlotRightGamepadKeyCode = HotbarBindings.SlotRightAction.GamepadBinding.KeyCode - export type Props = { forceGamepadHintVisible: boolean?, forceKeyboardHintVisible: boolean?, @@ -38,20 +33,6 @@ local function Hotbar(props: Props) end end - if next(children) then - -- Create default hints for equipping between hotbar slots - children.SlotLeftHint = React.createElement(HotbarHint, { - keyCode = SlotLeftGamepadKeyCode, - forceVisible = props.forceGamepadHintVisible, - order = -1, - }) - children.SlotRightHint = React.createElement(HotbarHint, { - keyCode = SlotRightGamepadKeyCode, - forceVisible = props.forceGamepadHintVisible, - order = 100, - }) - end - return React.createElement("Frame", { [React.Tag] = "Hotbar", }, children) diff --git a/src/Components/Inventory.luau b/src/Components/Inventory.luau index 75a621d0..31eab353 100644 --- a/src/Components/Inventory.luau +++ b/src/Components/Inventory.luau @@ -2,15 +2,9 @@ local React = require(script.Parent.Parent.Parent.react) -local InventoryHint = require(script.Parent.InventoryHint) local Searchbar = require(script.Parent.Searchbar) local Slot = require(script.Parent.Slot) -local InventoryBindings = script.Parent.Parent.Bindings.InventoryContext -local RemoveFromHotbarGamepadKeyCode = InventoryBindings.RemoveFromHotbarAction.GamepadBinding.KeyCode -local SelectSwapGamepadKeyCode = InventoryBindings.SelectSwapAction.GamepadBinding.KeyCode -local CloseInventoryGamepadKeyCode = InventoryBindings.CloseInventoryAction.GamepadBinding.KeyCode - export type Props = { forceHintVisible: boolean?, size: UDim2?, -- TODO: change size to use slots amount @@ -34,35 +28,10 @@ local function Inventory(props: Props) end return React.createElement("Frame", { - Size = props.size, - Visible = props.visible, [React.Tag] = "Inventory", }, { - Hints = React.createElement("Frame", { - [React.Tag] = "Hints", - }, { - RemoveFromHotbarHint = React.createElement(InventoryHint, { - keyCode = RemoveFromHotbarGamepadKeyCode, - forceVisible = props.forceHintVisible, - text = "Remove from hotbar", - }), - SelectSwapHint = React.createElement(InventoryHint, { - keyCode = SelectSwapGamepadKeyCode, - forceVisible = props.forceHintVisible, - text = "Select/Swap", - }), - CloseInventoryHint = React.createElement(InventoryHint, { - keyCode = CloseInventoryGamepadKeyCode, - forceVisible = props.forceHintVisible, - text = "Close inventory", - }), - }), - Slots = React.createElement("Frame", { - [React.Tag] = "Slots", - }, { - SearchBox = React.createElement(Searchbar), - SlotFrame = React.createElement("ScrollingFrame", nil, slotChildren), - }), + SearchBox = React.createElement(Searchbar), + SlotFrame = React.createElement("ScrollingFrame", nil, slotChildren), }) end diff --git a/src/Design.rbxmx b/src/Design.rbxmx index 272c3607..5958d61f 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,7 +11,58 @@ -1 - + + + + 0 + false + LegacyTheme + -1 + + + + + 0 + RBX3D69B4C35624443C8F53264528A35CD5 + + 0 + false + Derive from BaseTokens + -1 + + + + + + + + 0 + false + ThemeTokens + -1 + + + + -1 - + 0 - RBXE0F93419279746199C322A065DD297C3 + RBXA65C88D76FCF45D5938A72DB1A8642BE 0 false @@ -65,48 +116,19 @@ VGV4dFNpemU=]]> - - - - 0 - false - ThemeTokens - -1 - - - - + - + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= 0 false - LegacyTheme + DefaultTheme -1 - + 0 - RBX318BFD9CE35E4CD8848DAD895F5A8213 + RBX3D69B4C35624443C8F53264528A35CD5 0 false @@ -116,7 +138,7 @@ bmRDb2xvcg/NzMw+zczMPs3MzD4OAAAAVG9vbFRpcFBhZGRpbmcJAAAAAAIAAAA=]]> - + 0 @@ -125,266 +147,299 @@ bmRDb2xvcg/NzMw+zczMPs3MzD4OAAAAVG9vbFRpcFBhZGRpbmcJAAAAAAIAAAA=]]>-1 - + 0 - + - TextBox.Searchbar + .Hotbar 0 false - TextBox.Searchbar + .Hotbar -1 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= + AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= - ::UICorner + ::UIPadding 0 false - ::UICorner + ::UIPadding -1 - + 0 - + - >ImageButton + ::UIListLayout 0 false - >ImageButton + ::UIListLayout -1 - - - 0 - AAAAAA== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - + + + + 0 + + + .InventoryHint + + 0 + false + .InventoryHint + -1 + + + 0 - + - ::UIStroke + >TextLabel 0 false - ::UIStroke + >TextLabel -1 - + 0 - + - ::UIPadding + >ImageLabel 0 false - ::UIPadding + >ImageLabel -1 + + + 0 + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== + + ::UIAspectRatioConstraint + + 0 + false + ::UIAspectRatioConstraint + -1 + + + - + 0 - + - .HotbarHint + TextBox.Searchbar 0 false - .HotbarHint + TextBox.Searchbar -1 - + 0 - AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== + - ::UIAspectRatioConstraint + ::UIPadding 0 false - ::UIAspectRatioConstraint + ::UIPadding -1 - - - - 0 - - - .Hints - - 0 - false - .Hints - -1 - - - + 0 - + AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= - ::UIListLayout + ::UICorner 0 false - ::UIListLayout + ::UICorner -1 - - - - 0 - - - .Inventory - - 0 - false - .Inventory - -1 - - - + 0 - AAAAAA== + - ::UIListLayout + ::UIStroke 0 false - ::UIListLayout + ::UIStroke -1 + + + 0 + + + >ImageButton + + 0 + false + >ImageButton + -1 + + + + + 0 + AAAAAA== + + ::UIAspectRatioConstraint + + 0 + false + ::UIAspectRatioConstraint + -1 + + + + - + 0 - + - .Backpack + .HotbarHint 0 false - .Backpack + .HotbarHint -1 - + 0 - + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== - ::UIListLayout + ::UIAspectRatioConstraint 0 false - ::UIListLayout + ::UIAspectRatioConstraint -1 - + 0 - + - TextLabel.Tooltip + .Inventory 0 false - TextLabel.Tooltip + .Inventory -1 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz + - ::UICorner + >ScrollingFrame 0 false - ::UICorner + >ScrollingFrame -1 + + + 0 + + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + - + 0 - + ::UIPadding @@ -395,53 +450,24 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkVG9vbFRpcFBhZGRpbmc=]]> - - - - 0 - RBX9A9FAF7F89E64E39A8717BD548CA0A5D - - 0 - false - Derive from DefaultTheme - -1 - - - - - - 0 - - - .Hotbar - - 0 - false - .Hotbar - -1 - - - + 0 - AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz - ::UIPadding + ::UICorner 0 false - ::UIPadding + ::UICorner -1 - + 0 - + AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA ::UIListLayout @@ -453,117 +479,89 @@ aWdubWVudBURAAAAVmVydGljYWxBbGlnbm1lbnQAAAAA]]> - + 0 - + - TextButton.Slot + .Backpack 0 false - TextButton.Slot + .Backpack -1 - + 0 - AAAAAA== - - .Equipped - - 0 - false - .Equipped - -1 - - - - - 0 - - - ::UIStroke - - 0 - false - ::UIStroke - -1 - - - - - - - 0 - + - ::UIPadding + ::UIListLayout 0 false - ::UIPadding + ::UIListLayout -1 - - - 0 - - - .Unlocked - - 0 - false - .Unlocked - -1 - - - - - 0 - AAAAAA== - - :Press - - 0 - false - :Press - -1 - - - - - 0 - - - ::UIStroke - - 0 - false - ::UIStroke - -1 - - - - + + + + 0 + + + .Hints + + 0 + false + .Hints + -1 + + + + + 0 + + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + - + + + + 0 + + + TextButton.Slot + + 0 + false + TextButton.Slot + -1 + + + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== @@ -592,20 +590,20 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> - + 0 AAAAAA== - :Hover + :Press 0 false - :Hover + :Press -1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -620,35 +618,53 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> - + + + 0 + + + ::UITextSizeConstraint + + 0 + false + ::UITextSizeConstraint + -1 + + + + 0 AAAAAA== - :Press + .Equipped 0 false - :Press + .Equipped -1 - + 0 - AQAAAAcAAABWaXNpYmxlAwE= + - >.Tooltip + ::UIStroke 0 false - >.Tooltip + ::UIStroke -1 - + 0 AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= @@ -661,57 +677,42 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> -1 - + 0 - + AQAAAAcAAABWaXNpYmxlAwA= - .SlotNumber + .Tooltip 0 false - .SlotNumber + .Tooltip -1 - + 0 - AQAAAAcAAABWaXNpYmxlAwA= + - .Tooltip + .SlotNumber 0 false - .Tooltip + .SlotNumber -1 - - - 0 - - - ::UITextSizeConstraint - - 0 - false - ::UITextSizeConstraint - -1 - - - - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz @@ -725,29 +726,12 @@ AAAAAAAoQA==]]> - - - - 0 - - - .Slots - - 0 - false - .Slots - -1 - - - + 0 - + ::UIPadding @@ -758,151 +742,137 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkU3VyZmFjZVBhZGRpbmc=]]> - - - 0 - AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA - - ::UIListLayout - - 0 - false - ::UIListLayout - -1 - - - - + 0 - + AAAAAA== - >ScrollingFrame + :Hover 0 false - >ScrollingFrame + :Hover -1 - + 0 - + AQAAAAcAAABWaXNpYmxlAwE= - ::UIListLayout + >.Tooltip 0 false - ::UIListLayout + >.Tooltip -1 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz + - ::UICorner + .Unlocked 0 false - ::UICorner + .Unlocked -1 + + + 0 + AAAAAA== + + :Press + + 0 + false + :Press + -1 + + + + + 0 + + + ::UIStroke + + 0 + false + ::UIStroke + -1 + + + + - + 0 - + - .InventoryHint + TextLabel.Tooltip 0 false - .InventoryHint + TextLabel.Tooltip -1 - + 0 - + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz - >ImageLabel + ::UICorner 0 false - >ImageLabel + ::UICorner -1 - - - 0 - AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - + 0 - + - >TextLabel + ::UIPadding 0 false - >TextLabel + ::UIPadding -1 - - - - AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= - 0 - false - DefaultTheme - -1 - - - + 0 - RBX318BFD9CE35E4CD8848DAD895F5A8213 + RBX265C92BCB44A41E98507A36DF7336D5B 0 false - Derive from BaseTokens + Derive from DefaultTheme -1 From c53926feccbd8c7665f89243ae646769ea372ce9 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 6 Apr 2026 12:04:55 -0700 Subject: [PATCH 113/186] Remove gamepad hint props Signed-off-by: Ryan Luu --- src/Components/Hotbar.luau | 1 - src/Components/Inventory.luau | 1 - src/Stories/Hotbar.story.luau | 2 -- src/Stories/Inventory.story.luau | 2 -- 4 files changed, 6 deletions(-) diff --git a/src/Components/Hotbar.luau b/src/Components/Hotbar.luau index f580b18d..c8631462 100644 --- a/src/Components/Hotbar.luau +++ b/src/Components/Hotbar.luau @@ -5,7 +5,6 @@ local React = require(script.Parent.Parent.Parent.react) local Slot = require(script.Parent.Slot) export type Props = { - forceGamepadHintVisible: boolean?, forceKeyboardHintVisible: boolean?, slots: number?, tools: { Tool? }?, diff --git a/src/Components/Inventory.luau b/src/Components/Inventory.luau index 31eab353..6420aee8 100644 --- a/src/Components/Inventory.luau +++ b/src/Components/Inventory.luau @@ -6,7 +6,6 @@ local Searchbar = require(script.Parent.Searchbar) local Slot = require(script.Parent.Slot) export type Props = { - forceHintVisible: boolean?, size: UDim2?, -- TODO: change size to use slots amount tools: { Tool? }?, visible: boolean?, diff --git a/src/Stories/Hotbar.story.luau b/src/Stories/Hotbar.story.luau index 32a13e99..a3466393 100644 --- a/src/Stories/Hotbar.story.luau +++ b/src/Stories/Hotbar.story.luau @@ -5,7 +5,6 @@ local React = require(script.Parent.Parent.Parent.react) local Hotbar = require(script.Parent.Parent.Components.Hotbar) local controls = { - hintVisible = true, slots = 10, toolName = "Sword", toolImage = "rbxasset://Textures/Sword128.png", @@ -31,7 +30,6 @@ return { tools[props.controls.toolSlot] = tool return React.createElement(Hotbar, { - forceGamepadHintVisible = props.controls.hintVisible, slots = props.controls.slots, tools = tools, opened = props.controls.opened, diff --git a/src/Stories/Inventory.story.luau b/src/Stories/Inventory.story.luau index 0c263e18..6b53ae6b 100644 --- a/src/Stories/Inventory.story.luau +++ b/src/Stories/Inventory.story.luau @@ -5,7 +5,6 @@ local React = require(script.Parent.Parent.Parent.react) local Inventory = require(script.Parent.Parent.Components.Inventory) local controls = { - hintVisible = true, toolName = "Sword", toolImage = "rbxasset://Textures/Sword128.png", tooltipText = "A classic sword", @@ -29,7 +28,6 @@ return { tools[props.controls.toolSlot] = tool return React.createElement(Inventory, { - forceHintVisible = props.controls.hintVisible, size = UDim2.fromOffset(655, 300), tools = tools, }) From fe7b623c0c2ba382b67ac3ca5ac06dfa84ea62d0 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 6 Apr 2026 12:07:20 -0700 Subject: [PATCH 114/186] Remove old props Signed-off-by: Ryan Luu --- src/Components/Backpack.luau | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Components/Backpack.luau b/src/Components/Backpack.luau index 2f63dcba..3cc163ad 100644 --- a/src/Components/Backpack.luau +++ b/src/Components/Backpack.luau @@ -6,9 +6,9 @@ local Hotbar = require(script.Parent.Hotbar) local Inventory = require(script.Parent.Inventory) export type Props = { - forceGamepadHintVisible: boolean?, forceKeyboardHintVisible: boolean?, slots: number?, + rows: number?, -- TODO: Add rows for inventory height tools: { Tool? }?, opened: boolean?, } @@ -33,14 +33,12 @@ local function Backpack(props: Props) [React.Tag] = "Backpack", }, { Hotbar = React.createElement(Hotbar, { - forceGamepadHintVisible = props.forceGamepadHintVisible, forceKeyboardHintVisible = props.forceKeyboardHintVisible, slots = props.slots, tools = hotbarTools, opened = props.opened, }), Inventory = React.createElement(Inventory, { - forceHintVisible = props.forceGamepadHintVisible, slots = props.slots, tools = inventoryTools, visible = opened, From b64af562bd81d3cd2459b64a8485ad065b1a16d4 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 6 Apr 2026 12:29:54 -0700 Subject: [PATCH 115/186] Fix missing inventory prop Signed-off-by: Ryan Luu --- src/Components/Inventory.luau | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Components/Inventory.luau b/src/Components/Inventory.luau index 6420aee8..495d0868 100644 --- a/src/Components/Inventory.luau +++ b/src/Components/Inventory.luau @@ -27,6 +27,7 @@ local function Inventory(props: Props) end return React.createElement("Frame", { + Visible = props.visible, [React.Tag] = "Inventory", }, { SearchBox = React.createElement(Searchbar), From e9318ae4f82585a1b602332ed2964fe94ef3eadf Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 6 Apr 2026 12:31:42 -0700 Subject: [PATCH 116/186] Remove gamepad hint control Signed-off-by: Ryan Luu --- src/Stories/Backpack.story.luau | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Stories/Backpack.story.luau b/src/Stories/Backpack.story.luau index 4a93b80e..8e230220 100644 --- a/src/Stories/Backpack.story.luau +++ b/src/Stories/Backpack.story.luau @@ -5,7 +5,6 @@ local React = require(script.Parent.Parent.Parent.react) local Backpack = require(script.Parent.Parent.Components.Backpack) local controls = { - hintVisible = true, slots = 10, toolName = "Sword", toolImage = "rbxasset://Textures/Sword128.png", @@ -28,7 +27,6 @@ return { Tool.ToolTip = props.controls.toolTooltip return React.createElement(Backpack, { - forceGamepadHintVisible = props.controls.hintVisible, slots = props.controls.slots, tools = { [props.controls.toolSlot] = Tool }, opened = props.controls.opened, From 349d7597f5a926002a4205e09168dc29cbe5f704 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 6 Apr 2026 12:54:11 -0700 Subject: [PATCH 117/186] Fix using default prop Signed-off-by: Ryan Luu --- src/Components/Backpack.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Backpack.luau b/src/Components/Backpack.luau index 3cc163ad..f97076e3 100644 --- a/src/Components/Backpack.luau +++ b/src/Components/Backpack.luau @@ -36,7 +36,7 @@ local function Backpack(props: Props) forceKeyboardHintVisible = props.forceKeyboardHintVisible, slots = props.slots, tools = hotbarTools, - opened = props.opened, + opened = opened, }), Inventory = React.createElement(Inventory, { slots = props.slots, From 8ec02b8c9ab9d7eaba20b49e61987cfc0170240a Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 6 Apr 2026 12:57:40 -0700 Subject: [PATCH 118/186] Add basic app Signed-off-by: Ryan Luu --- src/Client.client.luau | 6 +- src/Components/App.luau | 76 ++++ src/Design.rbxmx | 740 +++++++++++++++++++------------------ src/Stories/App.story.luau | 37 ++ 4 files changed, 501 insertions(+), 358 deletions(-) create mode 100644 src/Components/App.luau create mode 100644 src/Stories/App.story.luau diff --git a/src/Client.client.luau b/src/Client.client.luau index 968680bb..e058525a 100644 --- a/src/Client.client.luau +++ b/src/Client.client.luau @@ -7,7 +7,7 @@ local StarterGui = game:GetService("StarterGui") local React = require(script.Parent.Parent.react) local ReactRoblox = require(script.Parent.Parent["react-roblox"]) -local Backpack = require(script.Parent.Components.Backpack) +local App = require(script.Parent.Components.App) local DESIGN_SHEET = script.Parent.Design.SatchelStyleSheet @@ -64,7 +64,7 @@ local function Satchel() end end, {}) - return React.createElement(Backpack, { + return React.createElement(App, { slots = slots, opened = opened, }) @@ -74,5 +74,5 @@ root:render(React.createElement(React.Fragment, nil, { StyleLink = React.createElement("StyleLink", { StyleSheet = DESIGN_SHEET, }), - Satchel = React.createElement(Satchel), + App = React.createElement(App), })) diff --git a/src/Components/App.luau b/src/Components/App.luau new file mode 100644 index 00000000..09d59f7c --- /dev/null +++ b/src/Components/App.luau @@ -0,0 +1,76 @@ +--!strict + +local React = require(script.Parent.Parent.Parent.react) + +local Backpack = require(script.Parent.Backpack) +local HotbarHint = require(script.Parent.HotbarHint) +local InventoryHint = require(script.Parent.InventoryHint) + +local InventoryBindings = script.Parent.Parent.Bindings.InventoryContext +local RemoveFromHotbarGamepadKeyCode = InventoryBindings.RemoveFromHotbarAction.GamepadBinding.KeyCode +local SelectSwapGamepadKeyCode = InventoryBindings.SelectSwapAction.GamepadBinding.KeyCode +local CloseInventoryGamepadKeyCode = InventoryBindings.CloseInventoryAction.GamepadBinding.KeyCode + +local HotbarBindings = script.Parent.Parent.Bindings.HotbarContext +local SlotLeftGamepadKeyCode = HotbarBindings.SlotLeftAction.GamepadBinding.KeyCode +local SlotRightGamepadKeyCode = HotbarBindings.SlotRightAction.GamepadBinding.KeyCode + +export type Props = { + forceGamepadHintVisible: boolean?, + forceKeyboardHintVisible: boolean?, + slots: number?, + rows: number?, -- TODO: Add rows for inventory height + tools: { Tool? }?, + opened: boolean?, +} + +local function App(props: Props) + return React.createElement("Frame", { + [React.Tag] = "Backpack", + }, { + SlotLeftHint = React.createElement(HotbarHint, { + keyCode = SlotLeftGamepadKeyCode, + forceVisible = props.forceGamepadHintVisible, + order = -1, + }), + SlotRightHint = React.createElement(HotbarHint, { + keyCode = SlotRightGamepadKeyCode, + forceVisible = props.forceGamepadHintVisible, + order = 1, + }), + InventoryHints = React.createElement("Frame", { + [React.Tag] = "InventoryHints", + + }, { + Hints = React.createElement("Frame", { + [React.Tag] = "Hints", + LayoutOrder = -1, + }, { + RemoveFromHotbarHint = React.createElement(InventoryHint, { + keyCode = RemoveFromHotbarGamepadKeyCode, + forceVisible = props.forceGamepadHintVisible, + text = "Remove from hotbar", + }), + SelectSwapHint = React.createElement(InventoryHint, { + keyCode = SelectSwapGamepadKeyCode, + forceVisible = props.forceGamepadHintVisible, + text = "Select/Swap", + }), + CloseInventoryHint = React.createElement(InventoryHint, { + keyCode = CloseInventoryGamepadKeyCode, + forceVisible = props.forceGamepadHintVisible, + text = "Close inventory", + }), + }), + Backpack = React.createElement(Backpack, { + forceKeyboardHintVisible = props.forceKeyboardHintVisible, + slots = props.slots, + rows = props.rows, + tools = props.tools, + opened = props.opened, + }), + }), + }) +end + +return App diff --git a/src/Design.rbxmx b/src/Design.rbxmx index 5958d61f..10ba8e3d 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,7 +11,29 @@ -1 - + + + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= + 0 + false + DefaultTheme + -1 + + + + + 0 + RBXF16540ED211D41469C898F210E938E63 + + 0 + false + Derive from BaseTokens + -1 + + + + + -1 - + 0 - RBX3D69B4C35624443C8F53264528A35CD5 + RBXF16540ED211D41469C898F210E938E63 0 false @@ -46,23 +68,7 @@ bmRDb2xvcg/NzMw+zczMPs3MzD4OAAAAVG9vbFRpcFBhZGRpbmcJAAAAAAIAAAA=]]> - - - - 0 - false - ThemeTokens - -1 - - - - + -1 - + 0 - RBXA65C88D76FCF45D5938A72DB1A8642BE + RBXFA4A37E41CFF4DC6B4F2A57B9AC13F02 0 false @@ -116,29 +122,23 @@ VGV4dFNpemU=]]> - + - AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= + 0 false - DefaultTheme + ThemeTokens -1 - - - 0 - RBX3D69B4C35624443C8F53264528A35CD5 - - 0 - false - Derive from BaseTokens - -1 - - - - + 0 @@ -147,40 +147,28 @@ VGV4dFNpemU=]]> -1 - + 0 - + - .Hotbar + .Backpack 0 false - .Hotbar + .Backpack -1 - - - 0 - AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= - - ::UIPadding - - 0 - false - ::UIPadding - -1 - - - - + 0 - + ::UIListLayout @@ -192,96 +180,31 @@ aWdubWVudBURAAAAVmVydGljYWxBbGlnbm1lbnQAAAAA]]> - - - 0 - - - .InventoryHint - - 0 - false - .InventoryHint - -1 - - - - - 0 - - - >TextLabel - - 0 - false - >TextLabel - -1 - - - - - - 0 - - - >ImageLabel - - 0 - false - >ImageLabel - -1 - - - - - 0 - AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - - - + 0 - + - TextBox.Searchbar + TextLabel.Tooltip 0 false - TextBox.Searchbar + TextLabel.Tooltip -1 - + 0 - + ::UIPadding @@ -292,10 +215,10 @@ ZwoAAABQYWRkaW5nVG9wAg4AAAAkU2VhcmNoUGFkZGluZw==]]> - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz ::UICorner @@ -306,84 +229,20 @@ ZwoAAABQYWRkaW5nVG9wAg4AAAAkU2VhcmNoUGFkZGluZw==]]> - - - 0 - - - ::UIStroke - - 0 - false - ::UIStroke - -1 - - - - - - 0 - - - >ImageButton - - 0 - false - >ImageButton - -1 - - - - - 0 - AAAAAA== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - - + 0 - - - .HotbarHint + RBX2F3F7E8ACD274A72B6BA41CBD70E035C 0 false - .HotbarHint + Derive from DefaultTheme -1 - - - 0 - AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - + 0 -1 - + 0 -1 - + 0 - + 0 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz @@ -464,7 +323,7 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkU3VyZmFjZVBhZGRpbmc=]]> - + 0 AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA @@ -479,70 +338,70 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkU3VyZmFjZVBhZGRpbmc=]]> - + 0 - + - .Backpack + .InventoryHint 0 false - .Backpack + .InventoryHint -1 - + 0 - + - ::UIListLayout + >TextLabel 0 false - ::UIListLayout + >TextLabel -1 - - - - 0 - - - .Hints - - 0 - false - .Hints - -1 - - - + 0 - + - ::UIListLayout + >ImageLabel 0 false - ::UIListLayout + >ImageLabel -1 + + + 0 + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== + + ::UIAspectRatioConstraint + + 0 + false + ::UIAspectRatioConstraint + -1 + + + - + 0 -1 - + 0 - + AAAAAA== - >ImageLabel + .Equipped 0 false - >ImageLabel + .Equipped -1 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== + - ::UICorner + ::UIStroke 0 false - ::UICorner + ::UIStroke -1 - + + + 0 + AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz + + ::UICorner + + 0 + false + ::UICorner + -1 + + + + 0 AAAAAA== - :Press + :Hover 0 false - :Press + :Hover -1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -618,53 +493,80 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> - + 0 - + - ::UITextSizeConstraint + >ImageLabel 0 false - ::UITextSizeConstraint + >ImageLabel -1 + + + 0 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== + + ::UICorner + + 0 + false + ::UICorner + -1 + + + - + + + 0 + + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + + 0 AAAAAA== - .Equipped + :Press 0 false - .Equipped + :Press -1 - + 0 - + AQAAAAcAAABWaXNpYmxlAwE= - ::UIStroke + >.Tooltip 0 false - ::UIStroke + >.Tooltip -1 - + 0 AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= @@ -677,7 +579,7 @@ b2luTW9kZQAAAAAJAAAAVGhpY2tuZXNzAhkAAAAkU2xvdEVxdWlwU3Ryb2tlVGhpY2tuZXNz -1 - + 0 AQAAAAcAAABWaXNpYmxlAwA= @@ -691,7 +593,7 @@ b2luTW9kZQAAAAAJAAAAVGhpY2tuZXNzAhkAAAAkU2xvdEVxdWlwU3Ryb2tlVGhpY2tuZXNz - + 0 - - - 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - - - 0 - - - ::UIPadding - - 0 - false - ::UIPadding - -1 - - - - + 0 - AAAAAA== + - :Hover + ::UITextSizeConstraint 0 false - :Hover + ::UITextSizeConstraint -1 - - - 0 - AQAAAAcAAABWaXNpYmxlAwE= - - >.Tooltip - - 0 - false - >.Tooltip - -1 - - - - + 0 -1 - + 0 AAAAAA== @@ -797,11 +656,12 @@ chYAAABCYWNrZ3JvdW5kVHJhbnNwYXJlbmN5BgAAAAAAAAAA]]> -1 - + 0 - + ::UIStroke @@ -815,45 +675,69 @@ b3ICFQAAACRTbG90UHJlc3NTdHJva2VDb2xvcgkAAABUaGlja25lc3MGAAAAAAAAAEA=]]> - + 0 - + - TextLabel.Tooltip + .HotbarHint 0 false - TextLabel.Tooltip + .HotbarHint -1 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== - ::UICorner + ::UIAspectRatioConstraint 0 false - ::UICorner + ::UIAspectRatioConstraint -1 - + + + + 0 + + + .Hotbar + + 0 + false + .Hotbar + -1 + + + 0 - + + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + + + + 0 + AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= ::UIPadding @@ -865,17 +749,163 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkVG9vbFRpcFBhZGRpbmc=]]> - + 0 - RBX265C92BCB44A41E98507A36DF7336D5B + + + .Hints 0 false - Derive from DefaultTheme + .Hints + -1 + + + + + 0 + + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + + + + + 0 + + + TextBox.Searchbar + + 0 + false + TextBox.Searchbar + -1 + + + + + 0 + + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + + + + 0 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= + + ::UICorner + + 0 + false + ::UICorner + -1 + + + + + + 0 + + + ::UIStroke + + 0 + false + ::UIStroke + -1 + + + + + + 0 + + + >ImageButton + + 0 + false + >ImageButton + -1 + + + + + 0 + AAAAAA== + + ::UIAspectRatioConstraint + + 0 + false + ::UIAspectRatioConstraint + -1 + + + + + + + + 7 + AAAAAA== + + .InventoryHints + + 0 + false + .InventoryHints -1 + + + 1 + AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + diff --git a/src/Stories/App.story.luau b/src/Stories/App.story.luau new file mode 100644 index 00000000..fa8fdf2e --- /dev/null +++ b/src/Stories/App.story.luau @@ -0,0 +1,37 @@ +--!strict + +local React = require(script.Parent.Parent.Parent.react) + +local App = require(script.Parent.Parent.Components.App) + +local controls = { + hintVisible = true, + slots = 10, + toolName = "Sword", + toolImage = "rbxasset://Textures/Sword128.png", + toolTooltip = "A classic sword", + toolSlot = 1, + opened = false, +} + +type Props = { + controls: typeof(controls), +} + +return { + summary = "Backpack that holds the hotbar and inventory", + controls = controls, + story = function(props: Props) + local Tool = Instance.new("Tool") + Tool.Name = props.controls.toolName + Tool.TextureId = props.controls.toolImage + Tool.ToolTip = props.controls.toolTooltip + + return React.createElement(App, { + forceGamepadHintVisible = props.controls.hintVisible, + slots = props.controls.slots, + tools = { [props.controls.toolSlot] = Tool }, + opened = props.controls.opened, + }) + end, +} From 86ded7d2694bd7e327a94c73066f3cce8f28003a Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 6 Apr 2026 13:58:41 -0700 Subject: [PATCH 119/186] Fix layout issues Signed-off-by: Ryan Luu --- src/Components/App.luau | 6 +- src/Design.rbxmx | 169 +++++++++++++++++++++++----------------- 2 files changed, 102 insertions(+), 73 deletions(-) diff --git a/src/Components/App.luau b/src/Components/App.luau index 09d59f7c..e1a3c203 100644 --- a/src/Components/App.luau +++ b/src/Components/App.luau @@ -26,7 +26,7 @@ export type Props = { local function App(props: Props) return React.createElement("Frame", { - [React.Tag] = "Backpack", + [React.Tag] = "HotbarHints", }, { SlotLeftHint = React.createElement(HotbarHint, { keyCode = SlotLeftGamepadKeyCode, @@ -40,11 +40,11 @@ local function App(props: Props) }), InventoryHints = React.createElement("Frame", { [React.Tag] = "InventoryHints", - }, { Hints = React.createElement("Frame", { + Visible = props.opened, + LayoutOrder = -1, [React.Tag] = "Hints", - LayoutOrder = -1, }, { RemoveFromHotbarHint = React.createElement(InventoryHint, { keyCode = RemoveFromHotbarGamepadKeyCode, diff --git a/src/Design.rbxmx b/src/Design.rbxmx index 10ba8e3d..f3b36670 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,7 +11,7 @@ -1 - + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= 0 @@ -20,10 +20,10 @@ -1 - + 0 - RBXF16540ED211D41469C898F210E938E63 + RBXF99B38BE5E774D7DBAB90E918A07E37F 0 false @@ -33,7 +33,7 @@ - + -1 - + 0 - RBXF16540ED211D41469C898F210E938E63 + RBXF99B38BE5E774D7DBAB90E918A07E37F 0 false @@ -68,7 +68,7 @@ bmRDb2xvcg/NzMw+zczMPs3MzD4OAAAAVG9vbFRpcFBhZGRpbmcJAAAAAAIAAAA=]]> - + -1 - + 0 - RBXFA4A37E41CFF4DC6B4F2A57B9AC13F02 + RBXE2DEAEF7B56A4B34AB81B17F877E01FC 0 false @@ -122,7 +122,7 @@ VGV4dFNpemU=]]> - + - + 0 @@ -147,12 +147,11 @@ Pw==]]> -1 - + 0 - + .Backpack @@ -162,13 +161,10 @@ c2l0aW9uCgAAAD8AAAAAAACAPwAAAAA=]]> -1 - + 0 - + AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= ::UIListLayout @@ -180,7 +176,7 @@ Z25tZW50AgAAAA==]]> - + 0 -1 - + 0 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz @@ -230,10 +226,10 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkVG9vbFRpcFBhZGRpbmc=]]> - + 0 - RBX2F3F7E8ACD274A72B6BA41CBD70E035C + RBX7D2E45B3A6D54919B3B847ABF4EBDA0F 0 false @@ -242,7 +238,7 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkVG9vbFRpcFBhZGRpbmc=]]> - + 0 -1 - + 0 -1 - + 0 - + 0 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz @@ -323,7 +319,7 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkU3VyZmFjZVBhZGRpbmc=]]> - + 0 AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA @@ -338,7 +334,7 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkU3VyZmFjZVBhZGRpbmc=]]> - + 0 -1 - + 0 - + 0 -1 - + 0 AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== @@ -401,7 +397,7 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAAAAACUAAAAAAAAAJQAAAA==]]> - + 0 -1 - + 0 AAAAAA== @@ -433,7 +429,7 @@ cmFuc3BhcmVuY3kMAAAAVGV4dFRydW5jYXRlFQwAAABUZXh0VHJ1bmNhdGUCAAAA]]>-1 - + 0 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz @@ -465,7 +461,7 @@ b2luTW9kZQAAAAAJAAAAVGhpY2tuZXNzAhkAAAAkU2xvdEVxdWlwU3Ryb2tlVGhpY2tuZXNz - + 0 AAAAAA== @@ -478,7 +474,7 @@ b2luTW9kZQAAAAAJAAAAVGhpY2tuZXNzAhkAAAAkU2xvdEVxdWlwU3Ryb2tlVGhpY2tuZXNz -1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -493,7 +489,7 @@ b2luTW9kZQAAAAAJAAAAVGhpY2tuZXNzAhkAAAAkU2xvdEVxdWlwU3Ryb2tlVGhpY2tuZXNz - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== @@ -522,7 +518,7 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> - + 0 - + 0 AAAAAA== @@ -551,7 +547,7 @@ YWRkaW5nVG9wAgwAAAAkU2xvdFBhZGRpbmc=]]> -1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -566,7 +562,7 @@ YWRkaW5nVG9wAgwAAAAkU2xvdFBhZGRpbmc=]]> - + 0 AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= @@ -579,7 +575,7 @@ YWRkaW5nVG9wAgwAAAAkU2xvdFBhZGRpbmc=]]> -1 - + 0 AQAAAAcAAABWaXNpYmxlAwA= @@ -593,7 +589,7 @@ YWRkaW5nVG9wAgwAAAAkU2xvdFBhZGRpbmc=]]> - + 0 - + 0 - + 0 -1 - + 0 AAAAAA== @@ -656,7 +652,7 @@ chYAAABCYWNrZ3JvdW5kVHJhbnNwYXJlbmN5BgAAAAAAAAAA]]> -1 - + 0 - + 0 -1 - + 0 AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== @@ -704,7 +700,7 @@ AAAAU2NhbGVUeXBlAwAAAAQAAABTaXplCgAAAAA8AAAAAAAAADwAAAA=]]> - + 0 -1 - + 0 - + 0 AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= @@ -749,7 +745,7 @@ aWdubWVudBURAAAAVmVydGljYWxBbGlnbm1lbnQAAAAA]]> - + 0 -1 - + 0 - + 0 -1 - + 0 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= @@ -831,7 +827,7 @@ ZwoAAABQYWRkaW5nVG9wAg4AAAAkU2VhcmNoUGFkZGluZw==]]> - + 0 - + 0 -1 - + 0 AAAAAA== @@ -879,10 +875,11 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAAcAAABWaXNpYmxlAwA=]]> - + 7 - AAAAAA== + .InventoryHints @@ -892,7 +889,7 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAAcAAABWaXNpYmxlAwA=]]> -1 - + 1 AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= @@ -907,6 +904,38 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAAcAAABWaXNpYmxlAwA=]]> + + + 8 + + + .HotbarHints + + 0 + false + .HotbarHints + -1 + + + + + 1 + + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + + \ No newline at end of file From aede77ec05a5de427f9329aff8d44d0131265c53 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 6 Apr 2026 14:50:35 -0700 Subject: [PATCH 120/186] Fix hotbar hints Signed-off-by: Ryan Luu --- src/Components/HotbarHint.luau | 7 +- src/Design.rbxmx | 988 +++++++++++++++++---------------- 2 files changed, 507 insertions(+), 488 deletions(-) diff --git a/src/Components/HotbarHint.luau b/src/Components/HotbarHint.luau index 861006e4..46cc5c24 100644 --- a/src/Components/HotbarHint.luau +++ b/src/Components/HotbarHint.luau @@ -36,11 +36,14 @@ local function HotbarHint(props: Props) local visible = props.forceVisible or isGamepadPreferred - return React.createElement("ImageLabel", { - Image = UserInputService:GetImageForKeyCode(props.keyCode), + return React.createElement("Frame", { LayoutOrder = props.order, Visible = visible, [React.Tag] = "HotbarHint", + }, { + KeyCode = React.createElement("ImageLabel", { + Image = UserInputService:GetImageForKeyCode(props.keyCode), + }), }) end diff --git a/src/Design.rbxmx b/src/Design.rbxmx index f3b36670..1d716017 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,7 +11,7 @@ -1 - + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= 0 @@ -20,10 +20,10 @@ -1 - + 0 - RBXF99B38BE5E774D7DBAB90E918A07E37F + RBX4A13E612DC02410A95FBBCCAFBBB01A3 0 false @@ -33,112 +33,7 @@ - - - - 0 - false - LegacyTheme - -1 - - - - - 0 - RBXF99B38BE5E774D7DBAB90E918A07E37F - - 0 - false - Derive from BaseTokens - -1 - - - - - - - - 0 - false - BaseTokens - -1 - - - - - 0 - RBXE2DEAEF7B56A4B34AB81B17F877E01FC - - 0 - false - Derive from ThemeTokens - -1 - - - - - - - - 0 - false - ThemeTokens - -1 - - - - + 0 @@ -147,182 +42,89 @@ Pw==]]> -1 - - - 0 - - - .Backpack - - 0 - false - .Backpack - -1 - - - - - 0 - AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= - - ::UIListLayout - - 0 - false - ::UIListLayout - -1 - - - - - + 0 - + - TextLabel.Tooltip + .InventoryHint 0 false - TextLabel.Tooltip + .InventoryHint -1 - - - 0 - - - ::UIPadding - - 0 - false - ::UIPadding - -1 - - - - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz + - ::UICorner + >TextLabel 0 false - ::UICorner + >TextLabel -1 - - - - 0 - RBX7D2E45B3A6D54919B3B847ABF4EBDA0F - - 0 - false - Derive from DefaultTheme - -1 - - - - - - 0 - - - .Inventory - - 0 - false - .Inventory - -1 - - - + 0 - + - >ScrollingFrame + >ImageLabel 0 false - >ScrollingFrame + >ImageLabel -1 - + 0 - + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== - ::UIListLayout + ::UIAspectRatioConstraint 0 false - ::UIListLayout + ::UIAspectRatioConstraint -1 - - - 0 - - - ::UIPadding - - 0 - false - ::UIPadding - -1 - - - - - - 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - + + + + 0 + + + .Hints + + 0 + false + .Hints + -1 + + + 0 - AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA + ::UIListLayout @@ -334,134 +136,116 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkU3VyZmFjZVBhZGRpbmc=]]> - + 0 - + - .InventoryHint + TextButton.Slot 0 false - .InventoryHint + TextButton.Slot -1 - + 0 - + AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz - >TextLabel + ::UICorner 0 false - >TextLabel + ::UICorner -1 - + 0 - + - >ImageLabel + ::UIPadding 0 false - >ImageLabel + ::UIPadding -1 - - - 0 - AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - - - - 0 - - - TextButton.Slot - - 0 - false - TextButton.Slot - -1 - - - + 0 - AAAAAA== + - .Equipped + .Unlocked 0 false - .Equipped + .Unlocked -1 - + 0 - + AAAAAA== - ::UIStroke + :Press 0 false - ::UIStroke + :Press -1 + + + 0 + + + ::UIStroke + + 0 + false + ::UIStroke + -1 + + + - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz + - ::UICorner + ::UITextSizeConstraint 0 false - ::UICorner + ::UITextSizeConstraint -1 - + 0 AAAAAA== @@ -474,7 +258,7 @@ b2luTW9kZQAAAAAJAAAAVGhpY2tuZXNzAhkAAAAkU2xvdEVxdWlwU3Ryb2tlVGhpY2tuZXNz -1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -489,7 +273,7 @@ b2luTW9kZQAAAAAJAAAAVGhpY2tuZXNzAhkAAAAkU2xvdEVxdWlwU3Ryb2tlVGhpY2tuZXNz - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== @@ -518,164 +302,291 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> - + 0 - + AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= - ::UIPadding + >TextLabel 0 false - ::UIPadding + >TextLabel -1 + + + 0 + + + .SlotNumber + + 0 + false + .SlotNumber + -1 + + + + + + 0 + AQAAAAcAAABWaXNpYmxlAwA= + + .Tooltip + + 0 + false + .Tooltip + -1 + + + - + 0 AAAAAA== - :Press + .Equipped 0 false - :Press + .Equipped -1 - + 0 - AQAAAAcAAABWaXNpYmxlAwE= + - >.Tooltip + ::UIStroke 0 false - >.Tooltip + ::UIStroke -1 - + 0 - AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= + AAAAAA== - >TextLabel + :Press 0 false - >TextLabel + :Press -1 - - - 0 - AQAAAAcAAABWaXNpYmxlAwA= - - .Tooltip - - 0 - false - .Tooltip - -1 - - - - + 0 - + AQAAAAcAAABWaXNpYmxlAwE= - .SlotNumber + >.Tooltip 0 false - .SlotNumber + >.Tooltip -1 - + + + + 8 + + + .HotbarHints + + 0 + false + .HotbarHints + -1 + + + + + 1 + + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + + + + + 7 + + + .InventoryHints + + 0 + false + .InventoryHints + -1 + + + + + 1 + AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + + + + + 0 + + + TextBox.Searchbar + + 0 + false + TextBox.Searchbar + -1 + + + 0 - + AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= - ::UITextSizeConstraint + ::UICorner 0 false - ::UITextSizeConstraint + ::UICorner -1 - + 0 - + - .Unlocked + >ImageButton 0 false - .Unlocked + >ImageButton -1 - + 0 AAAAAA== - :Press + ::UIAspectRatioConstraint 0 false - :Press + ::UIAspectRatioConstraint -1 - - - 0 - - - ::UIStroke - - 0 - false - ::UIStroke - -1 - - - + + + 0 + + + ::UIStroke + + 0 + false + ::UIStroke + -1 + + + + + + 0 + + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + + + + + 0 + RBX43C4FAFDA3DC4265B8EB0997DB58846B + + 0 + false + Derive from DefaultTheme + -1 + + - + 0 - + .HotbarHint @@ -685,22 +596,38 @@ AAAAU2NhbGVUeXBlAwAAAAQAAABTaXplCgAAAAA8AAAAAAAAADwAAAA=]]> -1 - + - 0 - AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== + 1 + - ::UIAspectRatioConstraint + >ImageLabel 0 false - ::UIAspectRatioConstraint + >ImageLabel -1 + + + 0 + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== + + ::UIAspectRatioConstraint + + 0 + false + ::UIAspectRatioConstraint + -1 + + + - + 0 -1 - + 0 - + AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= - ::UIListLayout + ::UIPadding 0 false - ::UIListLayout + ::UIPadding -1 - + 0 - AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= + - ::UIPadding + ::UIListLayout 0 false - ::UIPadding + ::UIListLayout -1 - + 0 - + - .Hints + TextLabel.Tooltip 0 false - .Hints + TextLabel.Tooltip -1 - + 0 - + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz - ::UIListLayout + ::UICorner 0 false - ::UIListLayout + ::UICorner + -1 + + + + + + 0 + + + ::UIPadding + + 0 + false + ::UIPadding -1 - + 0 - + - TextBox.Searchbar + .Inventory 0 false - TextBox.Searchbar + .Inventory -1 - + 0 - + AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA - ::UIPadding + ::UIListLayout 0 false - ::UIPadding + ::UIListLayout -1 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= + - ::UICorner + ::UIPadding 0 false - ::UICorner + ::UIPadding -1 - + 0 - + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz - ::UIStroke + ::UICorner 0 false - ::UIStroke + ::UICorner -1 - + 0 - + - >ImageButton + >ScrollingFrame 0 false - >ImageButton + >ScrollingFrame -1 - + 0 - AAAAAA== + - ::UIAspectRatioConstraint + ::UIListLayout 0 false - ::UIAspectRatioConstraint + ::UIListLayout -1 - + - 7 + 0 - .InventoryHints + .Backpack 0 false - .InventoryHints + .Backpack -1 - + - 1 + 0 AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= ::UIListLayout @@ -904,38 +847,111 @@ dW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/]]> - + + + + + 0 + false + LegacyTheme + -1 + + + - 8 - - - .HotbarHints + 0 + RBX4A13E612DC02410A95FBBCCAFBBB01A3 0 false - .HotbarHints + Derive from BaseTokens + -1 + + + + + + + + 0 + false + BaseTokens + -1 + + + + + 0 + RBXC47EF2C464AA442886831FFC0AD56ABC + + 0 + false + Derive from ThemeTokens -1 - - - 1 - - - ::UIListLayout - - 0 - false - ::UIListLayout - -1 - - - + + + + 0 + false + ThemeTokens + -1 + + + \ No newline at end of file From ade6a9c38594ea0963152cd401a95479b90d27cd Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 6 Apr 2026 15:11:33 -0700 Subject: [PATCH 121/186] Polish props and stories Signed-off-by: Ryan Luu --- src/Components/Backpack.luau | 2 +- src/Components/Inventory.luau | 5 +++-- src/Stories/App.story.luau | 2 +- src/Stories/Backpack.story.luau | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Components/Backpack.luau b/src/Components/Backpack.luau index f97076e3..19cc31a9 100644 --- a/src/Components/Backpack.luau +++ b/src/Components/Backpack.luau @@ -41,7 +41,7 @@ local function Backpack(props: Props) Inventory = React.createElement(Inventory, { slots = props.slots, tools = inventoryTools, - visible = opened, + opened = opened, }), }) end diff --git a/src/Components/Inventory.luau b/src/Components/Inventory.luau index 495d0868..113cfdc8 100644 --- a/src/Components/Inventory.luau +++ b/src/Components/Inventory.luau @@ -8,7 +8,7 @@ local Slot = require(script.Parent.Slot) export type Props = { size: UDim2?, -- TODO: change size to use slots amount tools: { Tool? }?, - visible: boolean?, + opened: boolean?, } local function Inventory(props: Props) @@ -27,7 +27,8 @@ local function Inventory(props: Props) end return React.createElement("Frame", { - Visible = props.visible, + Size = props.size, + Visible = props.opened, [React.Tag] = "Inventory", }, { SearchBox = React.createElement(Searchbar), diff --git a/src/Stories/App.story.luau b/src/Stories/App.story.luau index fa8fdf2e..c4d1d692 100644 --- a/src/Stories/App.story.luau +++ b/src/Stories/App.story.luau @@ -11,7 +11,7 @@ local controls = { toolImage = "rbxasset://Textures/Sword128.png", toolTooltip = "A classic sword", toolSlot = 1, - opened = false, + opened = true, } type Props = { diff --git a/src/Stories/Backpack.story.luau b/src/Stories/Backpack.story.luau index 8e230220..f646b045 100644 --- a/src/Stories/Backpack.story.luau +++ b/src/Stories/Backpack.story.luau @@ -10,7 +10,7 @@ local controls = { toolImage = "rbxasset://Textures/Sword128.png", toolTooltip = "A classic sword", toolSlot = 1, - opened = false, + opened = true, } type Props = { From 87c453f5f98de8f9093b46f7bb56a54e44926808 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 6 Apr 2026 15:20:46 -0700 Subject: [PATCH 122/186] Fix inventory hint sizing Signed-off-by: Ryan Luu --- src/Components/App.luau | 4 ++++ src/Components/Backpack.luau | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/src/Components/App.luau b/src/Components/App.luau index e1a3c203..15dbde93 100644 --- a/src/Components/App.luau +++ b/src/Components/App.luau @@ -25,6 +25,8 @@ export type Props = { } local function App(props: Props) + local backpackSize, setBackpackSize = React.useState(Vector2.zero) + return React.createElement("Frame", { [React.Tag] = "HotbarHints", }, { @@ -44,6 +46,7 @@ local function App(props: Props) Hints = React.createElement("Frame", { Visible = props.opened, LayoutOrder = -1, + Size = UDim2.fromOffset(backpackSize.X, 0), [React.Tag] = "Hints", }, { RemoveFromHotbarHint = React.createElement(InventoryHint, { @@ -68,6 +71,7 @@ local function App(props: Props) rows = props.rows, tools = props.tools, opened = props.opened, + onAbsoluteSizeChanged = setBackpackSize, }), }), }) diff --git a/src/Components/Backpack.luau b/src/Components/Backpack.luau index 19cc31a9..5c461b8d 100644 --- a/src/Components/Backpack.luau +++ b/src/Components/Backpack.luau @@ -11,6 +11,7 @@ export type Props = { rows: number?, -- TODO: Add rows for inventory height tools: { Tool? }?, opened: boolean?, + onAbsoluteSizeChanged: ((Vector2) -> ())?, } local function Backpack(props: Props) @@ -31,6 +32,11 @@ local function Backpack(props: Props) return React.createElement("Frame", { [React.Tag] = "Backpack", + [React.Change.AbsoluteSize] = function(rbx) + if props.onAbsoluteSizeChanged then + props.onAbsoluteSizeChanged(rbx.AbsoluteSize) + end + end, }, { Hotbar = React.createElement(Hotbar, { forceKeyboardHintVisible = props.forceKeyboardHintVisible, From 7b8de5816472df53ab618adeb49b44de86b223f4 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 6 Apr 2026 15:24:37 -0700 Subject: [PATCH 123/186] Add padding Signed-off-by: Ryan Luu --- src/Design.rbxmx | 145 ++++++++++++++++++++++++----------------------- 1 file changed, 73 insertions(+), 72 deletions(-) diff --git a/src/Design.rbxmx b/src/Design.rbxmx index 1d716017..20f85b29 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,7 +11,7 @@ -1 - + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= 0 @@ -20,10 +20,10 @@ -1 - + 0 - RBX4A13E612DC02410A95FBBCCAFBBB01A3 + RBXC4C303C3152D42D4AD43A91E501D1225 0 false @@ -33,7 +33,7 @@ - + 0 @@ -42,7 +42,7 @@ -1 - + 0 -1 - + 0 - + 0 -1 - + 0 AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== @@ -105,7 +105,7 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAAAAACUAAAAAAAAAJQAAAA==]]> - + 0 -1 - + 0 - +RmxleBUPAAAAVUlGbGV4QWxpZ25tZW50BAAAAAcAAABQYWRkaW5nCQAAAAAFAAAABQAAAFdy +YXBzAwE=]]> ::UIListLayout @@ -136,7 +137,7 @@ RmxleBUPAAAAVUlGbGV4QWxpZ25tZW50BAAAAAUAAABXcmFwcwMB]]> - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz @@ -169,7 +170,7 @@ cmFuc3BhcmVuY3kMAAAAVGV4dFRydW5jYXRlFQwAAABUZXh0VHJ1bmNhdGUCAAAA]]> - + 0 - + 0 -1 - + 0 AAAAAA== @@ -212,7 +213,7 @@ chYAAABCYWNrZ3JvdW5kVHJhbnNwYXJlbmN5BgAAAAAAAAAA]]> -1 - + 0 - + 0 - + 0 AAAAAA== @@ -258,7 +259,7 @@ AAAAAAAoQA==]]> -1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -273,7 +274,7 @@ AAAAAAAoQA==]]> - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== @@ -302,7 +303,7 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> - + 0 AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= @@ -315,7 +316,7 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> -1 - + 0 - + 0 AQAAAAcAAABWaXNpYmxlAwA= @@ -350,7 +351,7 @@ AAAAVGV4dFlBbGlnbm1lbnQVDgAAAFRleHRZQWxpZ25tZW50AAAAAA==]]> - + 0 AAAAAA== @@ -363,7 +364,7 @@ AAAAVGV4dFlBbGlnbm1lbnQVDgAAAFRleHRZQWxpZ25tZW50AAAAAA==]]> -1 - + 0 - + 0 AAAAAA== @@ -394,7 +395,7 @@ b2luTW9kZQAAAAAJAAAAVGhpY2tuZXNzAhkAAAAkU2xvdEVxdWlwU3Ryb2tlVGhpY2tuZXNz -1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -410,9 +411,9 @@ b2luTW9kZQAAAAAJAAAAVGhpY2tuZXNzAhkAAAAkU2xvdEVxdWlwU3Ryb2tlVGhpY2tuZXNz - + - 8 + 0 @@ -425,9 +426,9 @@ c2l0aW9uCgAAAD8AAAAAAACAPwAAAAA=]]> -1 - + - 1 + 0 @@ -442,9 +443,9 @@ QWxpZ25tZW50AgAAAA==]]> - + - 7 + 0 @@ -456,9 +457,9 @@ dW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/]]> -1 - + - 1 + 0 AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= ::UIListLayout @@ -471,7 +472,7 @@ dW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/]]> - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= @@ -506,7 +507,7 @@ dBUOAAAAVGV4dFhBbGlnbm1lbnQAAAAA]]> - + 0 -1 - + 0 AAAAAA== @@ -537,7 +538,7 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAAcAAABWaXNpYmxlAwA=]]> - + 0 - + 0 - + 0 - RBX43C4FAFDA3DC4265B8EB0997DB58846B + RBX4D1197CB39254B2E8F19E1EF98368AD7 0 false @@ -582,7 +583,7 @@ ZwoAAABQYWRkaW5nVG9wAg4AAAAkU2VhcmNoUGFkZGluZw==]]> - + 0 -1 - + - 1 + 0 @@ -611,7 +612,7 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAA==]]> -1 - + 0 AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== @@ -627,7 +628,7 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAA==]]> - + 0 -1 - + 0 AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= @@ -655,7 +656,7 @@ dW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/CwAAAExheW91dE9yZGVyBgAAAAAAAPA/]]> - + 0 - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz @@ -705,7 +706,7 @@ ZXh0U2l6ZQ==]]> - + 0 - + 0 -1 - + 0 AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA @@ -752,7 +753,7 @@ AIA/AAAAAAAAAAAAAAAA]]> - + 0 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz @@ -782,7 +783,7 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkU3VyZmFjZVBhZGRpbmc=]]> - + 0 -1 - + 0 - + 0 -1 - + 0 AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= @@ -848,7 +849,7 @@ dW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/]]> - + -1 - + 0 - RBX4A13E612DC02410A95FBBCCAFBBB01A3 + RBXC4C303C3152D42D4AD43A91E501D1225 0 false @@ -883,7 +884,7 @@ bmRDb2xvcg/NzMw+zczMPs3MzD4OAAAAVG9vbFRpcFBhZGRpbmcJAAAAAAIAAAA=]]> - + -1 - + 0 - RBXC47EF2C464AA442886831FFC0AD56ABC + RBX6154F16BCD4A44398C2D6C23BA912D5E 0 false @@ -937,7 +938,7 @@ VGV4dFNpemU=]]> - + Date: Mon, 6 Apr 2026 15:34:53 -0700 Subject: [PATCH 124/186] Fix mounting Signed-off-by: Ryan Luu --- src/Client.client.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Client.client.luau b/src/Client.client.luau index e058525a..87f29b57 100644 --- a/src/Client.client.luau +++ b/src/Client.client.luau @@ -74,5 +74,5 @@ root:render(React.createElement(React.Fragment, nil, { StyleLink = React.createElement("StyleLink", { StyleSheet = DESIGN_SHEET, }), - App = React.createElement(App), + App = React.createElement(Satchel), })) From 768a2f0fcd397af4480ff9a3765d312810812091 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 6 Apr 2026 15:42:57 -0700 Subject: [PATCH 125/186] Add rows prop Signed-off-by: Ryan Luu --- src/Components/Backpack.luau | 1 + src/Components/Inventory.luau | 13 ++++++++++--- src/Stories/App.story.luau | 2 ++ src/Stories/Backpack.story.luau | 2 ++ src/Stories/Inventory.story.luau | 4 +++- 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/Components/Backpack.luau b/src/Components/Backpack.luau index 5c461b8d..5a5fb9ac 100644 --- a/src/Components/Backpack.luau +++ b/src/Components/Backpack.luau @@ -46,6 +46,7 @@ local function Backpack(props: Props) }), Inventory = React.createElement(Inventory, { slots = props.slots, + rows = props.rows, tools = inventoryTools, opened = opened, }), diff --git a/src/Components/Inventory.luau b/src/Components/Inventory.luau index 113cfdc8..74e4bd38 100644 --- a/src/Components/Inventory.luau +++ b/src/Components/Inventory.luau @@ -6,12 +6,17 @@ local Searchbar = require(script.Parent.Searchbar) local Slot = require(script.Parent.Slot) export type Props = { - size: UDim2?, -- TODO: change size to use slots amount + width: number?, + rows: number?, tools: { Tool? }?, opened: boolean?, } local function Inventory(props: Props) + local width = props.width or 0 + local rows = props.rows or 4 + local height = rows * 65 - 5 + local slotChildren = {} if props.tools then @@ -27,12 +32,14 @@ local function Inventory(props: Props) end return React.createElement("Frame", { - Size = props.size, + Size = UDim2.fromOffset(width, 0), Visible = props.opened, [React.Tag] = "Inventory", }, { SearchBox = React.createElement(Searchbar), - SlotFrame = React.createElement("ScrollingFrame", nil, slotChildren), + SlotFrame = React.createElement("ScrollingFrame", { + Size = UDim2.fromOffset(0, height), + }, slotChildren), }) end diff --git a/src/Stories/App.story.luau b/src/Stories/App.story.luau index c4d1d692..fbc77c60 100644 --- a/src/Stories/App.story.luau +++ b/src/Stories/App.story.luau @@ -12,6 +12,7 @@ local controls = { toolTooltip = "A classic sword", toolSlot = 1, opened = true, + rows = 4, } type Props = { @@ -32,6 +33,7 @@ return { slots = props.controls.slots, tools = { [props.controls.toolSlot] = Tool }, opened = props.controls.opened, + rows = props.controls.rows, }) end, } diff --git a/src/Stories/Backpack.story.luau b/src/Stories/Backpack.story.luau index f646b045..acbae5e3 100644 --- a/src/Stories/Backpack.story.luau +++ b/src/Stories/Backpack.story.luau @@ -11,6 +11,7 @@ local controls = { toolTooltip = "A classic sword", toolSlot = 1, opened = true, + rows = 4, } type Props = { @@ -30,6 +31,7 @@ return { slots = props.controls.slots, tools = { [props.controls.toolSlot] = Tool }, opened = props.controls.opened, + rows = props.controls.rows, }) end, } diff --git a/src/Stories/Inventory.story.luau b/src/Stories/Inventory.story.luau index 6b53ae6b..e1f23d2d 100644 --- a/src/Stories/Inventory.story.luau +++ b/src/Stories/Inventory.story.luau @@ -9,6 +9,7 @@ local controls = { toolImage = "rbxasset://Textures/Sword128.png", tooltipText = "A classic sword", toolSlot = 1, + rows = 4, } type Props = { @@ -28,7 +29,8 @@ return { tools[props.controls.toolSlot] = tool return React.createElement(Inventory, { - size = UDim2.fromOffset(655, 300), + rows = props.controls.rows, + width = 655, tools = tools, }) end, From 556a9d5c884a6f2a9066d01b471d83d1e23ee084 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 6 Apr 2026 19:40:10 -0700 Subject: [PATCH 126/186] Add sizing for rows Signed-off-by: Ryan Luu --- src/Client.client.luau | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Client.client.luau b/src/Client.client.luau index 87f29b57..22e14d48 100644 --- a/src/Client.client.luau +++ b/src/Client.client.luau @@ -45,14 +45,17 @@ local function Satchel() -- Change slots based on viewport display size local slots, setSlots = React.useState(10) + local rows, setRows = React.useState(4) React.useEffect(function() local function viewportDisplaySizeChanged() local viewportSize = GuiService.ViewportDisplaySize if viewportSize == Enum.DisplaySize.Small then setSlots(5) + setRows(3) else setSlots(10) + setRows(4) end end @@ -66,6 +69,7 @@ local function Satchel() return React.createElement(App, { slots = slots, + rows = rows, opened = opened, }) end From 637892bf060ab674cdc6d48921f0dad5d54a7780 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 6 Apr 2026 23:00:49 -0700 Subject: [PATCH 127/186] Disable Satchel when CoreGui is detected Signed-off-by: Ryan Luu --- src/CoreGuiWarn.client.luau | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/CoreGuiWarn.client.luau diff --git a/src/CoreGuiWarn.client.luau b/src/CoreGuiWarn.client.luau new file mode 100644 index 00000000..9dfce1df --- /dev/null +++ b/src/CoreGuiWarn.client.luau @@ -0,0 +1,14 @@ +--!strict + +local StarterGui = game:GetService("StarterGui") +local Satchel = require(script.Parent) + +task.spawn(function() + while task.wait(1) do + if StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Backpack) then + warn("[Satchel] CoreGui backpack detected. Disabling Satchel to prevent conflicts.") + Satchel.setEnabled(false) + break + end + end +end) From 485b37f209813313a745372c6204f4f18522cf38 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Tue, 7 Apr 2026 07:11:21 -0700 Subject: [PATCH 128/186] Improve slot sizing Signed-off-by: Ryan Luu --- src/Components/App.luau | 2 +- src/Design.rbxmx | 948 ++++++++++++++++++++-------------------- 2 files changed, 475 insertions(+), 475 deletions(-) diff --git a/src/Components/App.luau b/src/Components/App.luau index 15dbde93..23a8ad56 100644 --- a/src/Components/App.luau +++ b/src/Components/App.luau @@ -41,12 +41,12 @@ local function App(props: Props) order = 1, }), InventoryHints = React.createElement("Frame", { + Size = UDim2.fromOffset(backpackSize.X, 0), [React.Tag] = "InventoryHints", }, { Hints = React.createElement("Frame", { Visible = props.opened, LayoutOrder = -1, - Size = UDim2.fromOffset(backpackSize.X, 0), [React.Tag] = "Hints", }, { RemoveFromHotbarHint = React.createElement(InventoryHint, { diff --git a/src/Design.rbxmx b/src/Design.rbxmx index 20f85b29..bc73a838 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,7 +11,112 @@ -1 - + + + + 0 + false + LegacyTheme + -1 + + + + + 0 + RBX71D54FC2039C474FA3BB1CC15A5EE3E5 + + 0 + false + Derive from BaseTokens + -1 + + + + + + + + 0 + false + BaseTokens + -1 + + + + + 0 + RBXBE006AE1D2E44615B8FCE3240D90942D + + 0 + false + Derive from ThemeTokens + -1 + + + + + + + + 0 + false + ThemeTokens + -1 + + + + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= 0 @@ -20,10 +125,10 @@ -1 - + 0 - RBXC4C303C3152D42D4AD43A91E501D1225 + RBX71D54FC2039C474FA3BB1CC15A5EE3E5 0 false @@ -33,7 +138,7 @@ - + 0 @@ -42,44 +147,76 @@ -1 - + 0 - + - .InventoryHint + TextLabel.Tooltip 0 false - .InventoryHint + TextLabel.Tooltip -1 - + 0 - + - >TextLabel + ::UIPadding 0 false - >TextLabel + ::UIPadding -1 - + 0 - + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz + + ::UICorner + + 0 + false + ::UICorner + -1 + + + + + + + 0 + + + .HotbarHint + + 0 + false + .HotbarHint + -1 + + + + + 0 + >ImageLabel @@ -89,10 +226,10 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAAAAACUAAAAAAAAAJQAAAA==]]> -1 - + 0 - AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== ::UIAspectRatioConstraint @@ -105,27 +242,27 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAAAAACUAAAAAAAAAJQAAAA==]]> - + 0 - + - .Hints + .HotbarHints 0 false - .Hints + .HotbarHints -1 - + 0 - + ::UIListLayout @@ -137,7 +274,7 @@ YXBzAwE=]]> - + 0 -1 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz + AAAAAA== - ::UICorner + :Hover 0 false - ::UICorner + :Hover -1 + + + 0 + AQAAAAcAAABWaXNpYmxlAwE= + + >.Tooltip + + 0 + false + >.Tooltip + -1 + + + - + 0 - + - ::UIPadding + ::UITextSizeConstraint 0 false - ::UIPadding + ::UITextSizeConstraint -1 - + 0 - + - .Unlocked + >ImageLabel 0 false - .Unlocked + >ImageLabel -1 - + 0 - AAAAAA== + AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== - :Press + ::UICorner 0 false - :Press + ::UICorner -1 - - - 0 - - - ::UIStroke - - 0 - false - ::UIStroke - -1 - - - - + 0 - + AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz - ::UITextSizeConstraint + ::UICorner 0 false - ::UITextSizeConstraint + ::UICorner -1 - + 0 AAAAAA== - :Hover + :Press 0 false - :Hover + :Press -1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -274,190 +407,162 @@ AAAAAAAoQA==]]> - + 0 - + - >ImageLabel + ::UIPadding 0 false - >ImageLabel + ::UIPadding -1 - - - 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - + 0 - AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= + AAAAAA== - >TextLabel + .Equipped 0 false - >TextLabel + .Equipped -1 - - - 0 - - - .SlotNumber - - 0 - false - .SlotNumber - -1 - - - - + 0 - AQAAAAcAAABWaXNpYmxlAwA= + - .Tooltip + ::UIStroke 0 false - .Tooltip + ::UIStroke -1 - + 0 - AAAAAA== + - .Equipped + .Unlocked 0 false - .Equipped + .Unlocked -1 - + 0 - + AAAAAA== - ::UIStroke + :Press 0 false - ::UIStroke + :Press -1 + + + 0 + + + ::UIStroke + + 0 + false + ::UIStroke + -1 + + + - + 0 - AAAAAA== + AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= - :Press + >TextLabel 0 false - :Press + >TextLabel -1 - + 0 - AQAAAAcAAABWaXNpYmxlAwE= + AQAAAAcAAABWaXNpYmxlAwA= - >.Tooltip + .Tooltip 0 false - >.Tooltip + .Tooltip + -1 + + + + + + 0 + + + .SlotNumber + + 0 + false + .SlotNumber -1 - - - 0 - - - .HotbarHints - - 0 - false - .HotbarHints - -1 - - - - - 0 - - - ::UIListLayout - - 0 - false - ::UIListLayout - -1 - - - - - + 0 - .InventoryHints + .Backpack 0 false - .InventoryHints + .Backpack -1 - + 0 AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= @@ -472,191 +577,160 @@ dW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/]]> - + 0 - + - TextBox.Searchbar + .Inventory 0 false - TextBox.Searchbar + .Inventory -1 - - - 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - + 0 - + - >ImageButton + >ScrollingFrame 0 false - >ImageButton + >ScrollingFrame -1 - + 0 - AAAAAA== + - ::UIAspectRatioConstraint + ::UIListLayout 0 false - ::UIAspectRatioConstraint + ::UIListLayout -1 - + 0 - + - ::UIStroke + ::UIPadding 0 false - ::UIStroke + ::UIPadding -1 - + 0 - + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz - ::UIPadding + ::UICorner 0 false - ::UIPadding + ::UICorner + -1 + + + + + + 0 + AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA + + ::UIListLayout + + 0 + false + ::UIListLayout -1 - + 0 - RBX4D1197CB39254B2E8F19E1EF98368AD7 + + + .InventoryHints 0 false - Derive from DefaultTheme + .InventoryHints -1 + + + 0 + AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + - + 0 - + - .HotbarHint + .Hotbar 0 false - .HotbarHint + .Hotbar -1 - + 0 - + AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= - >ImageLabel + ::UIPadding 0 false - >ImageLabel - -1 - - - - - 0 - AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - - - - - 0 - - - .Hotbar - - 0 - false - .Hotbar - -1 - - - - - 0 - AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= - - ::UIPadding - - 0 - false - ::UIPadding + ::UIPadding -1 - + 0 - + 0 - + RBX161950F0052E4CF9AE4227A0AC1DD08D + + 0 + false + Derive from DefaultTheme + -1 + + + + + + 0 + - TextLabel.Tooltip + TextBox.Searchbar 0 false - TextLabel.Tooltip + TextBox.Searchbar -1 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz + AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= ::UICorner @@ -706,12 +794,12 @@ ZXh0U2l6ZQ==]]> - + 0 - + ::UIPadding @@ -722,237 +810,149 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkVG9vbFRpcFBhZGRpbmc=]]> - - - - 0 - - - .Inventory - - 0 - false - .Inventory - -1 - - - + 0 - AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA + - ::UIListLayout + >ImageButton 0 false - ::UIListLayout + >ImageButton -1 + + + 0 + AAAAAA== + + ::UIAspectRatioConstraint + + 0 + false + ::UIAspectRatioConstraint + -1 + + + - + 0 - + - ::UIPadding + ::UIStroke 0 false - ::UIPadding + ::UIStroke -1 - + + + + 0 + + + .Hints + + 0 + false + .Hints + -1 + + + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz + - ::UICorner + ::UIListLayout 0 false - ::UICorner + ::UIListLayout -1 - + + + + 0 + + + .InventoryHint + + 0 + false + .InventoryHint + -1 + + + 0 - + - >ScrollingFrame + >ImageLabel 0 false - >ScrollingFrame + >ImageLabel -1 - + 0 - + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== - ::UIListLayout + ::UIAspectRatioConstraint 0 false - ::UIListLayout + ::UIAspectRatioConstraint -1 - - - - 0 - - - .Backpack - - 0 - false - .Backpack - -1 - - - + 0 - AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= + - ::UIListLayout + >TextLabel 0 false - ::UIListLayout + >TextLabel -1 - - - - 0 - false - LegacyTheme - -1 - - - - - 0 - RBXC4C303C3152D42D4AD43A91E501D1225 - - 0 - false - Derive from BaseTokens - -1 - - - - - - - - 0 - false - BaseTokens - -1 - - - - - 0 - RBX6154F16BCD4A44398C2D6C23BA912D5E - - 0 - false - Derive from ThemeTokens - -1 - - - - - - - - 0 - false - ThemeTokens - -1 - - - \ No newline at end of file From 829a27894b6a6ea9e8c900e1261191a07a0e0f67 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Tue, 7 Apr 2026 07:12:48 -0700 Subject: [PATCH 129/186] Rename keys Signed-off-by: Ryan Luu --- src/Components/InventoryHint.luau | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/InventoryHint.luau b/src/Components/InventoryHint.luau index c9c9e24c..da314b51 100644 --- a/src/Components/InventoryHint.luau +++ b/src/Components/InventoryHint.luau @@ -42,10 +42,10 @@ local function InventoryHint(props: Props) Visible = visible, [React.Tag] = "InventoryHint", }, { - Image = React.createElement("ImageLabel", { + KeyCode = React.createElement("ImageLabel", { Image = UserInputService:GetImageForKeyCode(props.keyCode), }), - KeyCode = React.createElement("TextLabel", { + Action = React.createElement("TextLabel", { Text = props.text, }), }) From 31d14c34f3582984bcf829c7d17e0613582f8c76 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Tue, 7 Apr 2026 07:25:30 -0700 Subject: [PATCH 130/186] Change story summary Signed-off-by: Ryan Luu --- src/Stories/App.story.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Stories/App.story.luau b/src/Stories/App.story.luau index fbc77c60..a7212708 100644 --- a/src/Stories/App.story.luau +++ b/src/Stories/App.story.luau @@ -20,7 +20,7 @@ type Props = { } return { - summary = "Backpack that holds the hotbar and inventory", + summary = "Hotbar and inventory, including hints for gamepad controls.", controls = controls, story = function(props: Props) local Tool = Instance.new("Tool") From cecab60fa1a742953ad902b1222c8d1561d49e99 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Tue, 7 Apr 2026 07:26:10 -0700 Subject: [PATCH 131/186] Fix inventory sizing Signed-off-by: Ryan Luu --- src/Components/Inventory.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Inventory.luau b/src/Components/Inventory.luau index 74e4bd38..ded6cd39 100644 --- a/src/Components/Inventory.luau +++ b/src/Components/Inventory.luau @@ -38,7 +38,7 @@ local function Inventory(props: Props) }, { SearchBox = React.createElement(Searchbar), SlotFrame = React.createElement("ScrollingFrame", { - Size = UDim2.fromOffset(0, height), + Size = UDim2.new(1, 0, 0, height), }, slotChildren), }) end From 7cc232158af85ee57c82ab25d3b566c9f74fa0c2 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Tue, 7 Apr 2026 07:26:32 -0700 Subject: [PATCH 132/186] Remove negative index logic Doesn't make sense and allows tools to be lost Signed-off-by: Ryan Luu --- src/Components/Backpack.luau | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Components/Backpack.luau b/src/Components/Backpack.luau index 5a5fb9ac..a0b6a669 100644 --- a/src/Components/Backpack.luau +++ b/src/Components/Backpack.luau @@ -16,16 +16,17 @@ export type Props = { local function Backpack(props: Props) local opened = props.opened or false + local slots = props.slots or 10 - -- Negative index for inventory and positive index for hotbar + -- Tools at indices 1..slots are hotbar; tools above slots are inventory. local hotbarTools: { [number]: Tool? } = {} local inventoryTools: { [number]: Tool? } = {} if props.tools then for index, tool in props.tools do - if tool and index > 0 then + if tool and index > 0 and index <= slots then hotbarTools[index] = tool - elseif tool and index < 0 then - inventoryTools[math.abs(index)] = tool + elseif tool and index > slots then + inventoryTools[index - slots] = tool end end end @@ -40,12 +41,12 @@ local function Backpack(props: Props) }, { Hotbar = React.createElement(Hotbar, { forceKeyboardHintVisible = props.forceKeyboardHintVisible, - slots = props.slots, + slots = slots, tools = hotbarTools, opened = opened, }), Inventory = React.createElement(Inventory, { - slots = props.slots, + slots = slots, rows = props.rows, tools = inventoryTools, opened = opened, From ef9e53390099709003b1421cae56f5124687f206 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Tue, 7 Apr 2026 07:32:31 -0700 Subject: [PATCH 133/186] Require tools to equip Signed-off-by: Ryan Luu --- src/Components/Slot.luau | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Components/Slot.luau b/src/Components/Slot.luau index 1d0b62a7..1a640866 100644 --- a/src/Components/Slot.luau +++ b/src/Components/Slot.luau @@ -77,7 +77,9 @@ local function Slot(props: Props) LayoutOrder = props.order, [React.Tag] = tags, [React.Event.Activated] = function() - setEquipped(not equipped) + if props.tool then + setEquipped(not equipped) + end end, }, { NumberHint = React.createElement("TextLabel", { From 94cc29b4053a9fd96835cc2f2553ec043d5fbd61 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Tue, 7 Apr 2026 07:47:25 -0700 Subject: [PATCH 134/186] Change slot equip color Signed-off-by: Ryan Luu --- src/Design.rbxmx | 982 +++++++++++++++++++++++------------------------ 1 file changed, 491 insertions(+), 491 deletions(-) diff --git a/src/Design.rbxmx b/src/Design.rbxmx index bc73a838..f1c6268c 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,112 +11,7 @@ -1 - - - - 0 - false - LegacyTheme - -1 - - - - - 0 - RBX71D54FC2039C474FA3BB1CC15A5EE3E5 - - 0 - false - Derive from BaseTokens - -1 - - - - - - - - 0 - false - BaseTokens - -1 - - - - - 0 - RBXBE006AE1D2E44615B8FCE3240D90942D - - 0 - false - Derive from ThemeTokens - -1 - - - - - - - - 0 - false - ThemeTokens - -1 - - - - + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= 0 @@ -125,10 +20,10 @@ Pw==]]> -1 - + 0 - RBX71D54FC2039C474FA3BB1CC15A5EE3E5 + RBXCE005181B47B45908F52AF52BB5594B0 0 false @@ -138,7 +33,7 @@ Pw==]]> - + 0 @@ -147,76 +42,44 @@ Pw==]]> -1 - + 0 - + - TextLabel.Tooltip + .InventoryHint 0 false - TextLabel.Tooltip + .InventoryHint -1 - - - 0 - - - ::UIPadding - - 0 - false - ::UIPadding - -1 - - - - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz + - ::UICorner + >TextLabel 0 false - ::UICorner + >TextLabel -1 - - - - 0 - - - .HotbarHint - - 0 - false - .HotbarHint - -1 - - - + 0 - + >ImageLabel @@ -226,10 +89,10 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAA==]]> -1 - + 0 - AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== ::UIAspectRatioConstraint @@ -242,27 +105,27 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAA==]]> - + 0 - + - .HotbarHints + .Hints 0 false - .HotbarHints + .Hints -1 - + 0 - + ::UIListLayout @@ -274,7 +137,7 @@ QWxpZ25tZW50AgAAAA==]]> - + 0 -1 - + 0 - AAAAAA== + AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz - :Hover + ::UICorner 0 false - :Hover + ::UICorner -1 - - - 0 - AQAAAAcAAABWaXNpYmxlAwE= - - >.Tooltip - - 0 - false - >.Tooltip - -1 - - - - + 0 - + - ::UITextSizeConstraint + ::UIPadding 0 false - ::UITextSizeConstraint + ::UIPadding -1 - + 0 - + - >ImageLabel + .Unlocked 0 false - >ImageLabel + .Unlocked -1 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== + AAAAAA== - ::UICorner + :Press 0 false - ::UICorner + :Press -1 + + + 0 + + + ::UIStroke + + 0 + false + ::UIStroke + -1 + + + - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz + - ::UICorner + ::UITextSizeConstraint 0 false - ::UICorner + ::UITextSizeConstraint -1 - + 0 AAAAAA== - :Press + :Hover 0 false - :Press + :Hover -1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -407,99 +274,36 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> - + 0 - + - ::UIPadding + >ImageLabel 0 false - ::UIPadding + >ImageLabel -1 - - - - 0 - AAAAAA== - - .Equipped - - 0 - false - .Equipped - -1 - - - - - 0 - - - ::UIStroke - - 0 - false - ::UIStroke - -1 - - - - - - - 0 - - - .Unlocked - - 0 - false - .Unlocked - -1 - - - + 0 - AAAAAA== + AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== - :Press + ::UICorner 0 false - :Press + ::UICorner -1 - - - 0 - - - ::UIStroke - - 0 - false - ::UIStroke - -1 - - - - + 0 AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= @@ -512,185 +316,122 @@ cgIVAAAAJFNsb3RQcmVzc1N0cm9rZUNvbG9yCQAAAFRoaWNrbmVzcwYAAAAAAAAAQA==]]>-1 - + 0 - AQAAAAcAAABWaXNpYmxlAwA= + - .Tooltip + .SlotNumber 0 false - .Tooltip + .SlotNumber -1 - + 0 - + AQAAAAcAAABWaXNpYmxlAwA= - .SlotNumber + .Tooltip 0 false - .SlotNumber + .Tooltip -1 - - - - 0 - - - .Backpack - - 0 - false - .Backpack - -1 - - - - - 0 - AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= - - ::UIListLayout - - 0 - false - ::UIListLayout - -1 - - - - - - - 0 - - - .Inventory - - 0 - false - .Inventory - -1 - - - + 0 - + AAAAAA== - >ScrollingFrame + .Equipped 0 false - >ScrollingFrame + .Equipped -1 - + 0 - + - ::UIListLayout + ::UIStroke 0 false - ::UIListLayout + ::UIStroke -1 - - - 0 - - - ::UIPadding - - 0 - false - ::UIPadding - -1 - - - - - - 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - + 0 - AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA + AAAAAA== - ::UIListLayout + :Press 0 false - ::UIListLayout + :Press -1 + + + 0 + AQAAAAcAAABWaXNpYmxlAwE= + + >.Tooltip + + 0 + false + >.Tooltip + -1 + + + - + 0 - + - .InventoryHints + .HotbarHints 0 false - .InventoryHints + .HotbarHints -1 - + 0 - AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= + ::UIListLayout @@ -702,40 +443,24 @@ dW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/]]> - + 0 - + - .Hotbar + .InventoryHints 0 false - .Hotbar + .InventoryHints -1 - - - 0 - AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= - - ::UIPadding - - 0 - false - ::UIPadding - -1 - - - - + 0 - + AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= ::UIListLayout @@ -747,19 +472,7 @@ aWdubWVudBURAAAAVmVydGljYWxBbGlnbm1lbnQAAAAA]]> - - - 0 - RBX161950F0052E4CF9AE4227A0AC1DD08D - - 0 - false - Derive from DefaultTheme - -1 - - - - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= @@ -794,23 +507,7 @@ dBUOAAAAVGV4dFhBbGlnbm1lbnQAAAAA]]> - - - 0 - - - ::UIPadding - - 0 - false - ::UIPadding - -1 - - - - + 0 -1 - + 0 AAAAAA== @@ -841,7 +538,7 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAAcAAABWaXNpYmxlAwA=]]> - + 0 - - + + + 0 + + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + + + 0 - + RBX83175D774C9846CBBD3D7C504CBAB73B + + 0 + false + Derive from DefaultTheme + -1 + + + + + + 0 + - .Hints + .HotbarHint 0 false - .Hints + .HotbarHint -1 - + 0 - + + + >ImageLabel + + 0 + false + >ImageLabel + -1 + + + + + 0 + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== + + ::UIAspectRatioConstraint + + 0 + false + ::UIAspectRatioConstraint + -1 + + + + + + + + 0 + + + .Hotbar + + 0 + false + .Hotbar + -1 + + + + + 0 + AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + + + + 0 + ::UIListLayout @@ -890,69 +673,286 @@ YXBzAwE=]]> - + 0 - + - .InventoryHint + TextLabel.Tooltip 0 false - .InventoryHint + TextLabel.Tooltip -1 - + 0 - + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz - >ImageLabel + ::UICorner 0 false - >ImageLabel + ::UICorner + -1 + + + + + + 0 + + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + + + + + 0 + + + .Inventory + + 0 + false + .Inventory + -1 + + + + + 0 + AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA + + ::UIListLayout + + 0 + false + ::UIListLayout -1 - + + + + 0 + + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + + + + 0 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz + + ::UICorner + + 0 + false + ::UICorner + -1 + + + + + + 0 + + + >ScrollingFrame + + 0 + false + >ScrollingFrame + -1 + + + 0 - AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== + - ::UIAspectRatioConstraint + ::UIListLayout 0 false - ::UIAspectRatioConstraint + ::UIListLayout -1 - + + + + 0 + + + .Backpack + + 0 + false + .Backpack + -1 + + + 0 - + AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= - >TextLabel + ::UIListLayout 0 false - >TextLabel + ::UIListLayout -1 + + + + 0 + false + LegacyTheme + -1 + + + + + 0 + RBXCE005181B47B45908F52AF52BB5594B0 + + 0 + false + Derive from BaseTokens + -1 + + + + + + + + 0 + false + BaseTokens + -1 + + + + + 0 + RBX682DCC87898346488B858E2027787DED + + 0 + false + Derive from ThemeTokens + -1 + + + + + + + + 0 + false + ThemeTokens + -1 + + + \ No newline at end of file From a2f18c2e58cd34a6eb534bf2e24e207702f12870 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Tue, 7 Apr 2026 08:00:34 -0700 Subject: [PATCH 135/186] Add search clear Signed-off-by: Ryan Luu --- src/Components/Searchbar.luau | 13 +- src/Design.rbxmx | 910 +++++++++++++++++----------------- 2 files changed, 467 insertions(+), 456 deletions(-) diff --git a/src/Components/Searchbar.luau b/src/Components/Searchbar.luau index 80565a17..9d71215f 100644 --- a/src/Components/Searchbar.luau +++ b/src/Components/Searchbar.luau @@ -7,11 +7,22 @@ export type Props = { } local function Searchbar(props: Props) + local text, setText = React.useState("") + return React.createElement("TextBox", { Size = props.size, + Text = text, [React.Tag] = "Searchbar", + [React.Change.Text] = function(rbx) + setText(rbx.Text) + end, }, { - Clear = React.createElement("ImageButton"), + Clear = React.createElement("ImageButton", { + Visible = text ~= "", + [React.Event.Activated] = function() + setText("") + end, + }), }) end diff --git a/src/Design.rbxmx b/src/Design.rbxmx index f1c6268c..4230a08a 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,7 +11,7 @@ -1 - + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= 0 @@ -20,10 +20,10 @@ -1 - + 0 - RBXCE005181B47B45908F52AF52BB5594B0 + RBXF034F2EE0BF74D04B4D39A0CE0EFC31F 0 false @@ -33,7 +33,42 @@ - + + + + 0 + false + LegacyTheme + -1 + + + + + 0 + RBXF034F2EE0BF74D04B4D39A0CE0EFC31F + + 0 + false + Derive from BaseTokens + -1 + + + + + 0 @@ -42,44 +77,26 @@ -1 - + 0 - + - .InventoryHint + .HotbarHint 0 false - .InventoryHint + .HotbarHint -1 - - - 0 - - - >TextLabel - - 0 - false - >TextLabel - -1 - - - - + 0 - + >ImageLabel @@ -89,10 +106,10 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAAAAACUAAAAAAAAAJQAAAA==]]> -1 - + 0 - AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== ::UIAspectRatioConstraint @@ -105,7 +122,7 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAAAAACUAAAAAAAAAJQAAAA==]]> - + 0 -1 - + 0 - + 0 - + RBX2FF6552E822F4E7FBAE03E67B8191F23 + + 0 + false + Derive from DefaultTheme + -1 + + + + + + 0 + - TextButton.Slot + .InventoryHint 0 false - TextButton.Slot + .InventoryHint -1 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz + - ::UICorner + >ImageLabel 0 false - ::UICorner + >ImageLabel -1 + + + 0 + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== + + ::UIAspectRatioConstraint + + 0 + false + ::UIAspectRatioConstraint + -1 + + + - + 0 - + - ::UIPadding + >TextLabel 0 false - ::UIPadding + >TextLabel -1 - + + + + 0 + + + .HotbarHints + + 0 + false + .HotbarHints + -1 + + + 0 - + - .Unlocked + ::UIListLayout 0 false - .Unlocked + ::UIListLayout -1 - - - 0 - AAAAAA== - - :Press - - 0 - false - :Press - -1 - - - - - 0 - - - ::UIStroke - - 0 - false - ::UIStroke - -1 - - - - - + + + + 0 + + + TextBox.Searchbar + + 0 + false + TextBox.Searchbar + -1 + + + 0 - + - ::UITextSizeConstraint + ::UIPadding 0 false - ::UITextSizeConstraint + ::UIPadding -1 - + 0 - AAAAAA== + - :Hover + ::UIStroke 0 false - :Hover + ::UIStroke -1 - - - 0 - AQAAAAcAAABWaXNpYmxlAwE= - - >.Tooltip - - 0 - false - >.Tooltip - -1 - - - - + 0 - + - >ImageLabel + >ImageButton 0 false - >ImageLabel + >ImageButton -1 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== + AAAAAA== - ::UICorner + ::UIAspectRatioConstraint 0 false - ::UICorner + ::UIAspectRatioConstraint -1 - + 0 - AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= + AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= - >TextLabel + ::UICorner 0 false - >TextLabel + ::UICorner -1 - - - 0 - - - .SlotNumber - - 0 - false - .SlotNumber - -1 - - - - - - 0 - AQAAAAcAAABWaXNpYmxlAwA= - - .Tooltip - - 0 - false - .Tooltip - -1 - - - - + + + + 0 + + + .Inventory + + 0 + false + .Inventory + -1 + + + 0 - AAAAAA== + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz - .Equipped + ::UICorner 0 false - .Equipped + ::UICorner -1 - - - 0 - - - ::UIStroke - - 0 - false - ::UIStroke - -1 - - - - + 0 - AAAAAA== + - :Press + >ScrollingFrame 0 false - :Press + >ScrollingFrame -1 - + 0 - AQAAAAcAAABWaXNpYmxlAwE= + - >.Tooltip + ::UIListLayout 0 false - >.Tooltip + ::UIListLayout -1 - - - - 0 - - - .HotbarHints - - 0 - false - .HotbarHints - -1 - - - + 0 - + - ::UIListLayout + ::UIPadding 0 false - ::UIListLayout + ::UIPadding -1 - - - - 0 - - - .InventoryHints - - 0 - false - .InventoryHints - -1 - - - + 0 - AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= + AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA ::UIListLayout @@ -472,419 +456,435 @@ dW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/]]> - + 0 - + - TextBox.Searchbar + TextLabel.Tooltip 0 false - TextBox.Searchbar + TextLabel.Tooltip -1 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= + - ::UICorner + ::UIPadding 0 false - ::UICorner + ::UIPadding -1 - + 0 - + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz - >ImageButton + ::UICorner 0 false - >ImageButton + ::UICorner -1 - - - 0 - AAAAAA== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - + + + + 0 + + + .Hotbar + + 0 + false + .Hotbar + -1 + + + 0 - + AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= - ::UIStroke + ::UIPadding 0 false - ::UIStroke + ::UIPadding -1 - + 0 - + - ::UIPadding + ::UIListLayout 0 false - ::UIPadding + ::UIListLayout -1 - + 0 - RBX83175D774C9846CBBD3D7C504CBAB73B + + + .InventoryHints 0 false - Derive from DefaultTheme + .InventoryHints -1 + + + 0 + AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + - + 0 - + - .HotbarHint + .Backpack 0 false - .HotbarHint + .Backpack -1 - + 0 - + AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= - >ImageLabel + ::UIListLayout 0 false - >ImageLabel + ::UIListLayout -1 - - - 0 - AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - + 0 - + - .Hotbar + TextButton.Slot 0 false - .Hotbar + TextButton.Slot -1 - + 0 - AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= + - ::UIPadding + ::UITextSizeConstraint 0 false - ::UIPadding + ::UITextSizeConstraint -1 - + 0 - + AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= - ::UIListLayout + >TextLabel 0 false - ::UIListLayout + >TextLabel -1 + + + 0 + + + .SlotNumber + + 0 + false + .SlotNumber + -1 + + + + + + 0 + AQAAAAcAAABWaXNpYmxlAwA= + + .Tooltip + + 0 + false + .Tooltip + -1 + + + - - - - 0 - - - TextLabel.Tooltip - - 0 - false - TextLabel.Tooltip - -1 - - - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz + - ::UICorner + ::UIPadding 0 false - ::UICorner + ::UIPadding -1 - + 0 - + - ::UIPadding + >ImageLabel 0 false - ::UIPadding + >ImageLabel -1 + + + 0 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== + + ::UICorner + + 0 + false + ::UICorner + -1 + + + - - - - 0 - - - .Inventory - - 0 - false - .Inventory - -1 - - - + 0 - AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA + AAAAAA== - ::UIListLayout + .Equipped 0 false - ::UIListLayout + .Equipped -1 + + + 0 + + + ::UIStroke + + 0 + false + ::UIStroke + -1 + + + - + 0 - + - ::UIPadding + .Unlocked 0 false - ::UIPadding + .Unlocked -1 + + + 0 + AAAAAA== + + :Press + + 0 + false + :Press + -1 + + + + + 0 + + + ::UIStroke + + 0 + false + ::UIStroke + -1 + + + + - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz + AAAAAA== - ::UICorner + :Hover 0 false - ::UICorner + :Hover -1 + + + 0 + AQAAAAcAAABWaXNpYmxlAwE= + + >.Tooltip + + 0 + false + >.Tooltip + -1 + + + - + 0 - + AAAAAA== - >ScrollingFrame + :Press 0 false - >ScrollingFrame + :Press -1 - + 0 - + AQAAAAcAAABWaXNpYmxlAwE= - ::UIListLayout + >.Tooltip 0 false - ::UIListLayout + >.Tooltip -1 - - - - 0 - - - .Backpack - - 0 - false - .Backpack - -1 - - - + 0 - AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= + AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz - ::UIListLayout + ::UICorner 0 false - ::UIListLayout + ::UICorner -1 - - - - 0 - false - LegacyTheme - -1 - - - - - 0 - RBXCE005181B47B45908F52AF52BB5594B0 - - 0 - false - Derive from BaseTokens - -1 - - - - - + -1 - + 0 - RBX682DCC87898346488B858E2027787DED + RBX8FF8B8FC2D1F432EBA9D88C8E6061320 0 false @@ -938,7 +938,7 @@ VGV4dFNpemU=]]> - + Date: Tue, 7 Apr 2026 09:06:02 -0700 Subject: [PATCH 136/186] Fix function type Signed-off-by: Ryan Luu --- src/Components/Backpack.luau | 2 +- src/Components/Searchbar.luau | 2 +- src/Components/Slot.luau | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Components/Backpack.luau b/src/Components/Backpack.luau index a0b6a669..9bd1085c 100644 --- a/src/Components/Backpack.luau +++ b/src/Components/Backpack.luau @@ -37,7 +37,7 @@ local function Backpack(props: Props) if props.onAbsoluteSizeChanged then props.onAbsoluteSizeChanged(rbx.AbsoluteSize) end - end, + end :: any, }, { Hotbar = React.createElement(Hotbar, { forceKeyboardHintVisible = props.forceKeyboardHintVisible, diff --git a/src/Components/Searchbar.luau b/src/Components/Searchbar.luau index 9d71215f..70a10f97 100644 --- a/src/Components/Searchbar.luau +++ b/src/Components/Searchbar.luau @@ -15,7 +15,7 @@ local function Searchbar(props: Props) [React.Tag] = "Searchbar", [React.Change.Text] = function(rbx) setText(rbx.Text) - end, + end :: any, }, { Clear = React.createElement("ImageButton", { Visible = text ~= "", diff --git a/src/Components/Slot.luau b/src/Components/Slot.luau index 1a640866..69b10bd4 100644 --- a/src/Components/Slot.luau +++ b/src/Components/Slot.luau @@ -80,7 +80,7 @@ local function Slot(props: Props) if props.tool then setEquipped(not equipped) end - end, + end :: any, }, { NumberHint = React.createElement("TextLabel", { Text = slotNumber, From 2a1b0108d90342a696d5d350c58cc62bed099919 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Tue, 7 Apr 2026 22:45:53 -0700 Subject: [PATCH 137/186] Add portrait backpack size Signed-off-by: Ryan Luu --- src/Client.client.luau | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/Client.client.luau b/src/Client.client.luau index 22e14d48..197ff162 100644 --- a/src/Client.client.luau +++ b/src/Client.client.luau @@ -48,22 +48,30 @@ local function Satchel() local rows, setRows = React.useState(4) React.useEffect(function() - local function viewportDisplaySizeChanged() + local function updateBackpackSize() + local screenOrientation = playerGui.CurrentScreenOrientation local viewportSize = GuiService.ViewportDisplaySize - if viewportSize == Enum.DisplaySize.Small then - setSlots(5) + + if screenOrientation == Enum.ScreenOrientation.Portrait then + setSlots(3) setRows(3) + elseif viewportSize == Enum.DisplaySize.Small then + setSlots(5) + setRows(2) else setSlots(10) setRows(4) end end - viewportDisplaySizeChanged() - local signal = GuiService:GetPropertyChangedSignal("ViewportDisplaySize"):Connect(viewportDisplaySizeChanged) + updateBackpackSize() + local viewportSignal = GuiService:GetPropertyChangedSignal("ViewportDisplaySize"):Connect(updateBackpackSize) + local orientationSignal = + playerGui:GetPropertyChangedSignal("CurrentScreenOrientation"):Connect(updateBackpackSize) return function() - signal:Disconnect() + viewportSignal:Disconnect() + orientationSignal:Disconnect() end end, {}) From ff02d746165e83eb0cb08b42167c967b93c654c7 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Tue, 7 Apr 2026 23:05:36 -0700 Subject: [PATCH 138/186] Close inventory on menu opened Signed-off-by: Ryan Luu --- src/Client.client.luau | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Client.client.luau b/src/Client.client.luau index 197ff162..d6b8553e 100644 --- a/src/Client.client.luau +++ b/src/Client.client.luau @@ -6,6 +6,7 @@ local StarterGui = game:GetService("StarterGui") local React = require(script.Parent.Parent.react) local ReactRoblox = require(script.Parent.Parent["react-roblox"]) +local closeInventory = require(script.Parent.Api.closeInventory) local App = require(script.Parent.Components.App) @@ -36,10 +37,14 @@ local function Satchel() local inventoryClosedSignal = bindableEvents.InventoryClosed.Event:Connect(function() setOpened(false) end) + local menuOpenedSignal = GuiService.MenuOpened:Connect(function() + closeInventory() + end) return function() inventoryOpenedSignal:Disconnect() inventoryClosedSignal:Disconnect() + menuOpenedSignal:Disconnect() end end, {}) From 88f4ffc6790aef3167fcfde0cbed07a19b78eaf6 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Wed, 8 Apr 2026 00:32:46 -0700 Subject: [PATCH 139/186] Add syntax highlighting for .rbxmx Signed-off-by: Ryan Luu --- .gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..86670b24 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.rbxmx linguist-language=XML From 0648ade7a05e8de663c338c1dcabc26bf29c726e Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Wed, 8 Apr 2026 00:36:57 -0700 Subject: [PATCH 140/186] Add click out behavior Clicking outside backpack should close it. In addition, the backpack now sinks inputs Signed-off-by: Ryan Luu --- src/Client.client.luau | 11 ++++ src/Design.rbxmx | 134 ++++++++++++++++++++--------------------- 2 files changed, 78 insertions(+), 67 deletions(-) diff --git a/src/Client.client.luau b/src/Client.client.luau index d6b8553e..f7909b34 100644 --- a/src/Client.client.luau +++ b/src/Client.client.luau @@ -3,6 +3,7 @@ local GuiService = game:GetService("GuiService") local Players = game:GetService("Players") local StarterGui = game:GetService("StarterGui") +local UserInputService = game:GetService("UserInputService") local React = require(script.Parent.Parent.react) local ReactRoblox = require(script.Parent.Parent["react-roblox"]) @@ -48,6 +49,16 @@ local function Satchel() end end, {}) + -- Close backpack when clicking outside of it + UserInputService.InputBegan:Connect(function(input: InputObject, gameProcessedEvent: boolean) + local inputType = input.UserInputType + if not gameProcessedEvent then + if inputType == Enum.UserInputType.MouseButton1 or inputType == Enum.UserInputType.Touch then + closeInventory() + end + end + end) + -- Change slots based on viewport display size local slots, setSlots = React.useState(10) local rows, setRows = React.useState(4) diff --git a/src/Design.rbxmx b/src/Design.rbxmx index 4230a08a..c7c7f4dd 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,7 +11,7 @@ -1 - + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= 0 @@ -20,10 +20,10 @@ -1 - + 0 - RBXF034F2EE0BF74D04B4D39A0CE0EFC31F + RBX82ABF0CF469E40EAAC93D8D654ECF2FC 0 false @@ -33,7 +33,7 @@ - + -1 - + 0 - RBXF034F2EE0BF74D04B4D39A0CE0EFC31F + RBX82ABF0CF469E40EAAC93D8D654ECF2FC 0 false @@ -68,7 +68,7 @@ bmRDb2xvcg/NzMw+zczMPs3MzD4OAAAAVG9vbFRpcFBhZGRpbmcJAAAAAAIAAAA=]]> - + 0 @@ -77,7 +77,7 @@ bmRDb2xvcg/NzMw+zczMPs3MzD4OAAAAVG9vbFRpcFBhZGRpbmcJAAAAAAIAAAA=]]>-1 - + 0 -1 - + 0 -1 - + 0 AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== @@ -122,7 +122,7 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAA==]]> - + 0 -1 - + 0 - + 0 - RBX2FF6552E822F4E7FBAE03E67B8191F23 + RBXA22B2273A3C846D8AF69CE842BE99BBB 0 false @@ -166,7 +166,7 @@ YXBzAwE=]]> - + 0 -1 - + 0 -1 - + 0 AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== @@ -210,7 +210,7 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAAAAACUAAAAAAAAAJQAAAA==]]> - + 0 - + 0 -1 - + 0 - + 0 -1 - + 0 - + 0 - + 0 -1 - + 0 AAAAAA== @@ -345,7 +345,7 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAA==]]> - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= @@ -360,7 +360,7 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAA==]]> - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz @@ -390,7 +390,7 @@ AIA/AAAAAAAAAAAAAAAA]]> - + 0 -1 - + 0 - + 0 - + 0 AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA @@ -456,7 +456,7 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkU3VyZmFjZVBhZGRpbmc=]]> - + 0 -1 - + 0 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz @@ -506,7 +506,7 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkVG9vbFRpcFBhZGRpbmc=]]> - + 0 -1 - + 0 AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= @@ -534,7 +534,7 @@ dW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/CwAAAExheW91dE9yZGVyBgAAAAAAAPA/]]> - + 0 - + 0 -1 - + 0 AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= @@ -580,11 +580,11 @@ dW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/]]> - + 0 - + .Backpack @@ -594,7 +594,7 @@ dW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/]]> -1 - + 0 AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= @@ -609,7 +609,7 @@ dW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/]]> - + 0 -1 - + 0 - + 0 AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= @@ -656,7 +656,7 @@ AAAAAAAoQA==]]> -1 - + 0 - + 0 AQAAAAcAAABWaXNpYmxlAwA= @@ -691,7 +691,7 @@ AAAAVGV4dFlBbGlnbm1lbnQVDgAAAFRleHRZQWxpZ25tZW50AAAAAA==]]> - + 0 - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== @@ -736,7 +736,7 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> - + 0 AAAAAA== @@ -749,7 +749,7 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> -1 - + 0 - + 0 -1 - + 0 AAAAAA== @@ -794,7 +794,7 @@ chYAAABCYWNrZ3JvdW5kVHJhbnNwYXJlbmN5BgAAAAAAAAAA]]> -1 - + 0 - + 0 AAAAAA== @@ -825,7 +825,7 @@ cgIVAAAAJFNsb3RQcmVzc1N0cm9rZUNvbG9yCQAAAFRoaWNrbmVzcwYAAAAAAAAAQA==]]>-1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -840,7 +840,7 @@ cgIVAAAAJFNsb3RQcmVzc1N0cm9rZUNvbG9yCQAAAFRoaWNrbmVzcwYAAAAAAAAAQA==]]> - + 0 AAAAAA== @@ -853,7 +853,7 @@ cgIVAAAAJFNsb3RQcmVzc1N0cm9rZUNvbG9yCQAAAFRoaWNrbmVzcwYAAAAAAAAAQA==]]>-1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -868,7 +868,7 @@ cgIVAAAAJFNsb3RQcmVzc1N0cm9rZUNvbG9yCQAAAFRoaWNrbmVzcwYAAAAAAAAAQA==]]> - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz @@ -884,7 +884,7 @@ cgIVAAAAJFNsb3RQcmVzc1N0cm9rZUNvbG9yCQAAAFRoaWNrbmVzcwYAAAAAAAAAQA==]]> - + -1 - + 0 - RBX8FF8B8FC2D1F432EBA9D88C8E6061320 + RBXABAC9F6B0A0A436FAEEA9B173F750FB4 0 false @@ -938,7 +938,7 @@ VGV4dFNpemU=]]> - + Date: Wed, 8 Apr 2026 00:37:19 -0700 Subject: [PATCH 141/186] Convert slot numbers to strings for keys Signed-off-by: Ryan Luu --- src/Components/Hotbar.luau | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Components/Hotbar.luau b/src/Components/Hotbar.luau index c8631462..8c109e90 100644 --- a/src/Components/Hotbar.luau +++ b/src/Components/Hotbar.luau @@ -23,6 +23,7 @@ local function Hotbar(props: Props) -- Only show slots if the hotbar is opened or if there is a tool in the slot if props.opened or tool then children[slotNumber] = React.createElement(Slot, { + key = tostring(slotNumber), order = slotNumber, tool = tool, hint = true, From c70350ac26d4b0b7cee89d1cde447285f507e7d9 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Wed, 8 Apr 2026 01:02:03 -0700 Subject: [PATCH 142/186] Add HopperBin support Signed-off-by: Ryan Luu --- src/Components/App.luau | 4 ++-- src/Components/Backpack.luau | 24 ++++++++++++------------ src/Components/Hotbar.luau | 10 +++++----- src/Components/Inventory.luau | 10 +++++----- src/Components/Slot.luau | 18 +++++++++--------- src/Stories/App.story.luau | 10 +++++----- src/Stories/Backpack.story.luau | 10 +++++----- src/Stories/Hotbar.story.luau | 5 +---- src/Stories/Inventory.story.luau | 5 +---- src/Stories/Slot.story.luau | 10 +++++----- 10 files changed, 50 insertions(+), 56 deletions(-) diff --git a/src/Components/App.luau b/src/Components/App.luau index 23a8ad56..a8ec8aca 100644 --- a/src/Components/App.luau +++ b/src/Components/App.luau @@ -20,7 +20,7 @@ export type Props = { forceKeyboardHintVisible: boolean?, slots: number?, rows: number?, -- TODO: Add rows for inventory height - tools: { Tool? }?, + items: { Tool | HopperBin }?, opened: boolean?, } @@ -69,7 +69,7 @@ local function App(props: Props) forceKeyboardHintVisible = props.forceKeyboardHintVisible, slots = props.slots, rows = props.rows, - tools = props.tools, + items = props.items, opened = props.opened, onAbsoluteSizeChanged = setBackpackSize, }), diff --git a/src/Components/Backpack.luau b/src/Components/Backpack.luau index 9bd1085c..988c9f11 100644 --- a/src/Components/Backpack.luau +++ b/src/Components/Backpack.luau @@ -9,7 +9,7 @@ export type Props = { forceKeyboardHintVisible: boolean?, slots: number?, rows: number?, -- TODO: Add rows for inventory height - tools: { Tool? }?, + items: { Tool | HopperBin }?, opened: boolean?, onAbsoluteSizeChanged: ((Vector2) -> ())?, } @@ -18,15 +18,15 @@ local function Backpack(props: Props) local opened = props.opened or false local slots = props.slots or 10 - -- Tools at indices 1..slots are hotbar; tools above slots are inventory. - local hotbarTools: { [number]: Tool? } = {} - local inventoryTools: { [number]: Tool? } = {} - if props.tools then - for index, tool in props.tools do - if tool and index > 0 and index <= slots then - hotbarTools[index] = tool - elseif tool and index > slots then - inventoryTools[index - slots] = tool + -- Items at indices 1..slots are hotbar; items above slots are inventory. + local hotbarItems: { [number]: Tool | HopperBin } = {} + local inventoryItems: { [number]: Tool | HopperBin } = {} + if props.items then + for index, item in props.items do + if item and index > 0 and index <= slots then + hotbarItems[index] = item + elseif item and index > slots then + inventoryItems[index - slots] = item end end end @@ -42,13 +42,13 @@ local function Backpack(props: Props) Hotbar = React.createElement(Hotbar, { forceKeyboardHintVisible = props.forceKeyboardHintVisible, slots = slots, - tools = hotbarTools, + items = hotbarItems, opened = opened, }), Inventory = React.createElement(Inventory, { slots = slots, rows = props.rows, - tools = inventoryTools, + items = inventoryItems, opened = opened, }), }) diff --git a/src/Components/Hotbar.luau b/src/Components/Hotbar.luau index 8c109e90..c60d7c1c 100644 --- a/src/Components/Hotbar.luau +++ b/src/Components/Hotbar.luau @@ -7,7 +7,7 @@ local Slot = require(script.Parent.Slot) export type Props = { forceKeyboardHintVisible: boolean?, slots: number?, - tools: { Tool? }?, + items: { Tool | HopperBin }?, opened: boolean?, } @@ -17,15 +17,15 @@ local function Hotbar(props: Props) local children = {} for slotNumber = 1, slotCount do - local tool = props.tools and props.tools[slotNumber] - local slotUnlocked = props.opened and tool ~= nil + local item = props.items and props.items[slotNumber] + local slotUnlocked = props.opened and item ~= nil -- Only show slots if the hotbar is opened or if there is a tool in the slot - if props.opened or tool then + if props.opened or item then children[slotNumber] = React.createElement(Slot, { key = tostring(slotNumber), order = slotNumber, - tool = tool, + item = item, hint = true, forceHintVisible = props.forceKeyboardHintVisible, unlocked = slotUnlocked, diff --git a/src/Components/Inventory.luau b/src/Components/Inventory.luau index ded6cd39..a914a428 100644 --- a/src/Components/Inventory.luau +++ b/src/Components/Inventory.luau @@ -8,7 +8,7 @@ local Slot = require(script.Parent.Slot) export type Props = { width: number?, rows: number?, - tools: { Tool? }?, + items: { Tool | HopperBin }?, opened: boolean?, } @@ -19,13 +19,13 @@ local function Inventory(props: Props) local slotChildren = {} - if props.tools then - for order, tool in props.tools do - if tool then + if props.items then + for order, item in props.items do + if item then slotChildren[order] = React.createElement(Slot, { unlocked = true, order = order, - tool = tool, + item = item, }) end end diff --git a/src/Components/Slot.luau b/src/Components/Slot.luau index 69b10bd4..93a0c4ce 100644 --- a/src/Components/Slot.luau +++ b/src/Components/Slot.luau @@ -7,7 +7,7 @@ local React = require(script.Parent.Parent.Parent.react) local Tooltip = require(script.Parent.Tooltip) export type Props = { - tool: Tool?, + item: (Tool | HopperBin)?, equipped: boolean?, unlocked: boolean?, forceHintVisible: boolean?, @@ -16,10 +16,10 @@ export type Props = { } local function Slot(props: Props) - local tool = props.tool - local toolName = tool and tool.Name - local toolImage = tool and tool.TextureId - local tooltipText = tool and tool.ToolTip + local item = props.item + local itemName = item and item.Name + local itemImage = item and item.TextureId + local tooltipText = item and (item:IsA("Tool") and item.ToolTip or "") local equipped, setEquipped = React.useState(props.equipped or false) @@ -67,8 +67,8 @@ local function Slot(props: Props) end -- Hide name if there is an image - local slotText = toolName - if toolImage ~= "" then + local slotText = itemName + if itemImage ~= "" then slotText = "" end @@ -77,7 +77,7 @@ local function Slot(props: Props) LayoutOrder = props.order, [React.Tag] = tags, [React.Event.Activated] = function() - if props.tool then + if props.item then setEquipped(not equipped) end end :: any, @@ -88,7 +88,7 @@ local function Slot(props: Props) [React.Tag] = "SlotNumber", }), TextureIcon = React.createElement("ImageLabel", { - Image = toolImage or "", + Image = itemImage or "", }), ToolTip = React.createElement(Tooltip, { text = tooltipText, diff --git a/src/Stories/App.story.luau b/src/Stories/App.story.luau index a7212708..a2e48a63 100644 --- a/src/Stories/App.story.luau +++ b/src/Stories/App.story.luau @@ -23,15 +23,15 @@ return { summary = "Hotbar and inventory, including hints for gamepad controls.", controls = controls, story = function(props: Props) - local Tool = Instance.new("Tool") - Tool.Name = props.controls.toolName - Tool.TextureId = props.controls.toolImage - Tool.ToolTip = props.controls.toolTooltip + local tool = Instance.new("Tool") + tool.Name = props.controls.toolName + tool.TextureId = props.controls.toolImage + tool.ToolTip = props.controls.toolTooltip return React.createElement(App, { forceGamepadHintVisible = props.controls.hintVisible, slots = props.controls.slots, - tools = { [props.controls.toolSlot] = Tool }, + items = { [props.controls.toolSlot] = tool }, opened = props.controls.opened, rows = props.controls.rows, }) diff --git a/src/Stories/Backpack.story.luau b/src/Stories/Backpack.story.luau index acbae5e3..ee42708e 100644 --- a/src/Stories/Backpack.story.luau +++ b/src/Stories/Backpack.story.luau @@ -22,14 +22,14 @@ return { summary = "Backpack that holds the hotbar and inventory", controls = controls, story = function(props: Props) - local Tool = Instance.new("Tool") - Tool.Name = props.controls.toolName - Tool.TextureId = props.controls.toolImage - Tool.ToolTip = props.controls.toolTooltip + local tool = Instance.new("Tool") + tool.Name = props.controls.toolName + tool.TextureId = props.controls.toolImage + tool.ToolTip = props.controls.toolTooltip return React.createElement(Backpack, { slots = props.controls.slots, - tools = { [props.controls.toolSlot] = Tool }, + items = { [props.controls.toolSlot] = tool }, opened = props.controls.opened, rows = props.controls.rows, }) diff --git a/src/Stories/Hotbar.story.luau b/src/Stories/Hotbar.story.luau index a3466393..896e4c59 100644 --- a/src/Stories/Hotbar.story.luau +++ b/src/Stories/Hotbar.story.luau @@ -26,12 +26,9 @@ return { tool.TextureId = props.controls.toolImage tool.ToolTip = props.controls.tooltipText - local tools = {} - tools[props.controls.toolSlot] = tool - return React.createElement(Hotbar, { slots = props.controls.slots, - tools = tools, + items = { [props.controls.toolSlot] = tool }, opened = props.controls.opened, }) end, diff --git a/src/Stories/Inventory.story.luau b/src/Stories/Inventory.story.luau index e1f23d2d..e2bf4d6a 100644 --- a/src/Stories/Inventory.story.luau +++ b/src/Stories/Inventory.story.luau @@ -25,13 +25,10 @@ return { tool.TextureId = props.controls.toolImage tool.ToolTip = props.controls.tooltipText - local tools = {} - tools[props.controls.toolSlot] = tool - return React.createElement(Inventory, { rows = props.controls.rows, width = 655, - tools = tools, + items = { [props.controls.toolSlot] = tool }, }) end, } diff --git a/src/Stories/Slot.story.luau b/src/Stories/Slot.story.luau index c5f52785..66085b47 100644 --- a/src/Stories/Slot.story.luau +++ b/src/Stories/Slot.story.luau @@ -22,13 +22,13 @@ return { summary = "Slot representing a single item in the hotbar or inventory, showing the tool and hints for equipping", controls = controls, story = function(props: Props) - local Tool = Instance.new("Tool") - Tool.Name = props.controls.toolName - Tool.TextureId = props.controls.toolImage - Tool.ToolTip = props.controls.toolTooltip + local tool = Instance.new("Tool") + tool.Name = props.controls.toolName + tool.TextureId = props.controls.toolImage + tool.ToolTip = props.controls.toolTooltip return React.createElement(Slot, { - tool = Tool, + item = tool, equipped = props.controls.equipped, unlocked = props.controls.unlocked, hint = props.controls.hint, From 618497ad1b4576260f0423b0b00a4f4098bc0e8b Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Wed, 8 Apr 2026 01:10:58 -0700 Subject: [PATCH 143/186] Add dev mode script for Roblox Studio Signed-off-by: Ryan Luu --- tests/DevMode.client.luau | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/DevMode.client.luau diff --git a/tests/DevMode.client.luau b/tests/DevMode.client.luau new file mode 100644 index 00000000..22167038 --- /dev/null +++ b/tests/DevMode.client.luau @@ -0,0 +1,3 @@ +local RunService = game:GetService("RunService") + +_G.__DEV__ = RunService:IsStudio() From 0f9f06d91c74035cc627da9069bcd16c11ff5fbc Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Wed, 8 Apr 2026 01:20:54 -0700 Subject: [PATCH 144/186] Add comments and rename variables Signed-off-by: Ryan Luu --- src/Components/Hotbar.luau | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Components/Hotbar.luau b/src/Components/Hotbar.luau index c60d7c1c..5b20b336 100644 --- a/src/Components/Hotbar.luau +++ b/src/Components/Hotbar.luau @@ -16,15 +16,16 @@ local function Hotbar(props: Props) local children = {} - for slotNumber = 1, slotCount do - local item = props.items and props.items[slotNumber] + -- Create hotbar slots + for order = 1, slotCount do + local item = props.items and props.items[order] local slotUnlocked = props.opened and item ~= nil -- Only show slots if the hotbar is opened or if there is a tool in the slot if props.opened or item then - children[slotNumber] = React.createElement(Slot, { - key = tostring(slotNumber), - order = slotNumber, + children[order] = React.createElement(Slot, { + key = tostring(order), + order = order, item = item, hint = true, forceHintVisible = props.forceKeyboardHintVisible, From 4d16ef55a065c226e2f608638507b657aee00cad Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Wed, 8 Apr 2026 01:25:35 -0700 Subject: [PATCH 145/186] Fix key behavior Signed-off-by: Ryan Luu --- src/Components/Hotbar.luau | 5 ++--- src/Components/Inventory.luau | 7 ++++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Components/Hotbar.luau b/src/Components/Hotbar.luau index 5b20b336..a3dbf6f9 100644 --- a/src/Components/Hotbar.luau +++ b/src/Components/Hotbar.luau @@ -14,7 +14,7 @@ export type Props = { local function Hotbar(props: Props) local slotCount = props.slots or 10 - local children = {} + local children: any = {} -- Create hotbar slots for order = 1, slotCount do @@ -23,8 +23,7 @@ local function Hotbar(props: Props) -- Only show slots if the hotbar is opened or if there is a tool in the slot if props.opened or item then - children[order] = React.createElement(Slot, { - key = tostring(order), + children[tostring(order)] = React.createElement(Slot, { order = order, item = item, hint = true, diff --git a/src/Components/Inventory.luau b/src/Components/Inventory.luau index a914a428..356de0c5 100644 --- a/src/Components/Inventory.luau +++ b/src/Components/Inventory.luau @@ -17,12 +17,13 @@ local function Inventory(props: Props) local rows = props.rows or 4 local height = rows * 65 - 5 - local slotChildren = {} + local children: any = {} + -- Create inventory slots if props.items then for order, item in props.items do if item then - slotChildren[order] = React.createElement(Slot, { + children[tostring(order)] = React.createElement(Slot, { unlocked = true, order = order, item = item, @@ -39,7 +40,7 @@ local function Inventory(props: Props) SearchBox = React.createElement(Searchbar), SlotFrame = React.createElement("ScrollingFrame", { Size = UDim2.new(1, 0, 0, height), - }, slotChildren), + }, children), }) end From 948f2563a52e6542d451d7c90fde3cabf6723ab1 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Wed, 8 Apr 2026 01:27:10 -0700 Subject: [PATCH 146/186] Remove useless controls Signed-off-by: Ryan Luu --- src/Stories/Inventory.story.luau | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Stories/Inventory.story.luau b/src/Stories/Inventory.story.luau index e2bf4d6a..e1488622 100644 --- a/src/Stories/Inventory.story.luau +++ b/src/Stories/Inventory.story.luau @@ -8,7 +8,6 @@ local controls = { toolName = "Sword", toolImage = "rbxasset://Textures/Sword128.png", tooltipText = "A classic sword", - toolSlot = 1, rows = 4, } @@ -28,7 +27,7 @@ return { return React.createElement(Inventory, { rows = props.controls.rows, width = 655, - items = { [props.controls.toolSlot] = tool }, + items = { [1] = tool }, }) end, } From 28216f574fad30b0f2de62ac0225e29abb2f1e23 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Wed, 8 Apr 2026 01:54:17 -0700 Subject: [PATCH 147/186] Remove completed TODO --- src/Components/App.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/App.luau b/src/Components/App.luau index a8ec8aca..40cc2c87 100644 --- a/src/Components/App.luau +++ b/src/Components/App.luau @@ -19,7 +19,7 @@ export type Props = { forceGamepadHintVisible: boolean?, forceKeyboardHintVisible: boolean?, slots: number?, - rows: number?, -- TODO: Add rows for inventory height + rows: number?, items: { Tool | HopperBin }?, opened: boolean?, } From 493bf8cd5a71970825188108f4e245446e2ee51b Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Wed, 8 Apr 2026 12:20:12 -0700 Subject: [PATCH 148/186] Add return types Signed-off-by: Ryan Luu --- src/Api/closeInventory.luau | 2 +- src/Api/getEnabled.luau | 2 +- src/Api/openInventory.luau | 2 +- src/Api/setEnabled.luau | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Api/closeInventory.luau b/src/Api/closeInventory.luau index 4bfdb5a7..f53e0841 100644 --- a/src/Api/closeInventory.luau +++ b/src/Api/closeInventory.luau @@ -4,7 +4,7 @@ local RunService = game:GetService("RunService") local bindableEvents = script.Parent.Parent.BindableEvents -local function closeInventory() +local function closeInventory(): () assert(RunService:IsClient(), "closeInventory can only be called on the client") bindableEvents.InventoryClosed:Fire() diff --git a/src/Api/getEnabled.luau b/src/Api/getEnabled.luau index 0e4a35da..18efbb59 100644 --- a/src/Api/getEnabled.luau +++ b/src/Api/getEnabled.luau @@ -7,7 +7,7 @@ local player = Players.LocalPlayer local playerGui = player:WaitForChild("PlayerGui") local screenGui = playerGui:WaitForChild("SatchelGui") -local function getEnabled() +local function getEnabled(): boolean assert(RunService:IsClient(), "getEnabled can only be called on the client") return screenGui.Enabled diff --git a/src/Api/openInventory.luau b/src/Api/openInventory.luau index d9723363..a3f6a73b 100644 --- a/src/Api/openInventory.luau +++ b/src/Api/openInventory.luau @@ -4,7 +4,7 @@ local RunService = game:GetService("RunService") local bindableEvents = script.Parent.Parent.BindableEvents -local function openInventory() +local function openInventory(): () assert(RunService:IsClient(), "openInventory can only be called on the client") bindableEvents.InventoryOpened:Fire() diff --git a/src/Api/setEnabled.luau b/src/Api/setEnabled.luau index ab623395..a0731e80 100644 --- a/src/Api/setEnabled.luau +++ b/src/Api/setEnabled.luau @@ -9,7 +9,7 @@ local player = Players.LocalPlayer local playerGui = player:WaitForChild("PlayerGui") local screenGui = playerGui:WaitForChild("SatchelGui") -local function setEnabled(isEnabled: boolean) +local function setEnabled(isEnabled: boolean): () assert(RunService:IsClient(), "setEnabled can only be called on the client") screenGui.Enabled = isEnabled From d584381623598adfa3ae375a5f55654730c9ca6b Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Wed, 8 Apr 2026 12:22:41 -0700 Subject: [PATCH 149/186] Shorten arg name Signed-off-by: Ryan Luu --- src/Api/setEnabled.luau | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Api/setEnabled.luau b/src/Api/setEnabled.luau index a0731e80..5b93604a 100644 --- a/src/Api/setEnabled.luau +++ b/src/Api/setEnabled.luau @@ -9,14 +9,14 @@ local player = Players.LocalPlayer local playerGui = player:WaitForChild("PlayerGui") local screenGui = playerGui:WaitForChild("SatchelGui") -local function setEnabled(isEnabled: boolean): () +local function setEnabled(enabled: boolean): () assert(RunService:IsClient(), "setEnabled can only be called on the client") - screenGui.Enabled = isEnabled + screenGui.Enabled = enabled local icon = getTopbarIcon() if icon then - icon:setEnabled(isEnabled) + icon:setEnabled(enabled) end end From 7adada58d02bd6d6b0c0609e310cbb712f8c63ee Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Wed, 8 Apr 2026 13:15:01 -0700 Subject: [PATCH 150/186] Fix icons being translated Signed-off-by: Ryan Luu --- src/TopbarIcon.client.luau | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/TopbarIcon.client.luau b/src/TopbarIcon.client.luau index a8b6c103..b08a9fe8 100644 --- a/src/TopbarIcon.client.luau +++ b/src/TopbarIcon.client.luau @@ -5,7 +5,10 @@ local Satchel = require(script.Parent) local icon = Icon.new() icon:setName("SatchelInventory") -icon:modifyTheme({ "IconLabelContainer", "TargetWidth", 0 }) -- Force minimum width +icon:modifyTheme({ + { "IconLabelContainer", "TargetWidth", 0 }, -- Force minimum width + { "IconLabel", "AutoLocalize", false }, -- Don't translate font icon +}) icon:setLabel("backpack") icon:setOrder(-1) icon:setTextSize(24) From f3336c755ec45f516954c271d13106b234b1b8ba Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Wed, 8 Apr 2026 13:15:19 -0700 Subject: [PATCH 151/186] Add theme APIs Signed-off-by: Ryan Luu --- src/Api/getTheme.luau | 14 +++++++ src/Api/setTheme.luau | 16 ++++++++ src/init.luau | 2 + ...lient.luau => CoreGuiBackpack.client.luau} | 0 tests/SwitchTheme.client.luau | 37 +++++++++++++++++++ ....client.luau => ToggleSatchel.client.luau} | 0 6 files changed, 69 insertions(+) create mode 100644 src/Api/getTheme.luau create mode 100644 src/Api/setTheme.luau rename tests/{ToggleCoreGui.client.luau => CoreGuiBackpack.client.luau} (100%) create mode 100644 tests/SwitchTheme.client.luau rename tests/{ToggleSatchelEnabled.client.luau => ToggleSatchel.client.luau} (100%) diff --git a/src/Api/getTheme.luau b/src/Api/getTheme.luau new file mode 100644 index 00000000..60b55796 --- /dev/null +++ b/src/Api/getTheme.luau @@ -0,0 +1,14 @@ +--!strict + +local RunService = game:GetService("RunService") + +local currentStyleSheet = script.Parent.Parent.Design.SatchelStyleSheet + +local function getTheme(): StyleSheet + assert(RunService:IsClient(), "getTheme can only be called on the client") + + local currentTheme = currentStyleSheet:FindFirstChildWhichIsA("StyleDerive").StyleSheet + return currentTheme +end + +return getTheme diff --git a/src/Api/setTheme.luau b/src/Api/setTheme.luau new file mode 100644 index 00000000..7ede6ea5 --- /dev/null +++ b/src/Api/setTheme.luau @@ -0,0 +1,16 @@ +--!strict + +local RunService = game:GetService("RunService") + +local styleSheets = script.Parent.Parent.Design +local currentTheme = styleSheets.SatchelStyleSheet:FindFirstChildWhichIsA("StyleDerive") + +-- TODO: Add autocomplete for default themes +local function setTheme(theme: string | StyleSheet) + assert(RunService:IsClient(), "setTheme can only be called on the client") + + local newTheme = if typeof(theme) == "string" then styleSheets:WaitForChild(theme) else theme + currentTheme.StyleSheet = newTheme +end + +return setTheme diff --git a/src/init.luau b/src/init.luau index d89cb384..75559cb7 100644 --- a/src/init.luau +++ b/src/init.luau @@ -6,6 +6,8 @@ return { -- Functions getEnabled = require(script.Api.getEnabled), setEnabled = require(script.Api.setEnabled), + getTheme = require(script.Api.getTheme), + setTheme = require(script.Api.setTheme), getTopbarIcon = require(script.Api.getTopbarIcon), openInventory = require(script.Api.openInventory), closeInventory = require(script.Api.closeInventory), diff --git a/tests/ToggleCoreGui.client.luau b/tests/CoreGuiBackpack.client.luau similarity index 100% rename from tests/ToggleCoreGui.client.luau rename to tests/CoreGuiBackpack.client.luau diff --git a/tests/SwitchTheme.client.luau b/tests/SwitchTheme.client.luau new file mode 100644 index 00000000..37a407d8 --- /dev/null +++ b/tests/SwitchTheme.client.luau @@ -0,0 +1,37 @@ +--!strict + +local Icon = require(script.Parent.Satchel.Packages.topbarplus) +local Satchel = require(script.Parent.Satchel) + +local switchThemeIcon = Icon.new() +switchThemeIcon:modifyTheme({ "IconLabelContainer", "TargetWidth", 0 }) -- Force minimum width +switchThemeIcon:setLabel("two-arrows-left-right") +switchThemeIcon:setTextSize(24) +switchThemeIcon:setTextFont( + "rbxasset://LuaPackages/Packages/_Index/BuilderIcons/BuilderIcons/BuilderIcons.json", + Enum.FontWeight.Bold, + Enum.FontStyle.Normal, + "Selected" +) +switchThemeIcon:setTextFont( + "rbxasset://LuaPackages/Packages/_Index/BuilderIcons/BuilderIcons/BuilderIcons.json", + Enum.FontWeight.Regular, + Enum.FontStyle.Normal, + "Deselected" +) +switchThemeIcon:setCaption("Switch Theme") +switchThemeIcon:align("Right") +switchThemeIcon:setDropdown({ + Icon.new() + :setLabel("Default") + :bindEvent("deselected", function() + Satchel.setTheme("DefaultTheme") + end) + :oneClick(), + Icon.new() + :setLabel("Legacy") + :bindEvent("deselected", function() + Satchel.setTheme("LegacyTheme") + end) + :oneClick(), +}) diff --git a/tests/ToggleSatchelEnabled.client.luau b/tests/ToggleSatchel.client.luau similarity index 100% rename from tests/ToggleSatchelEnabled.client.luau rename to tests/ToggleSatchel.client.luau From f02e38dc2feacf0cdc652be915a5a85c85d5ae75 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Wed, 8 Apr 2026 13:25:21 -0700 Subject: [PATCH 152/186] Update topbar icons Signed-off-by: Ryan Luu --- tests/SwitchTheme.client.luau | 21 ++++++++++++--------- tests/ToggleInventory.client.luau | 20 +++++++++++++++++++- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/tests/SwitchTheme.client.luau b/tests/SwitchTheme.client.luau index 37a407d8..ec039aa7 100644 --- a/tests/SwitchTheme.client.luau +++ b/tests/SwitchTheme.client.luau @@ -3,25 +3,28 @@ local Icon = require(script.Parent.Satchel.Packages.topbarplus) local Satchel = require(script.Parent.Satchel) -local switchThemeIcon = Icon.new() -switchThemeIcon:modifyTheme({ "IconLabelContainer", "TargetWidth", 0 }) -- Force minimum width -switchThemeIcon:setLabel("two-arrows-left-right") -switchThemeIcon:setTextSize(24) -switchThemeIcon:setTextFont( +local icon = Icon.new() +icon:modifyTheme({ + { "IconLabelContainer", "TargetWidth", 0 }, -- Force minimum width + { "IconLabel", "AutoLocalize", false }, -- Don't translate font icon +}) +icon:setLabel("two-arrows-left-right") +icon:align("Right") +icon:setTextSize(24) +icon:setTextFont( "rbxasset://LuaPackages/Packages/_Index/BuilderIcons/BuilderIcons/BuilderIcons.json", Enum.FontWeight.Bold, Enum.FontStyle.Normal, "Selected" ) -switchThemeIcon:setTextFont( +icon:setTextFont( "rbxasset://LuaPackages/Packages/_Index/BuilderIcons/BuilderIcons/BuilderIcons.json", Enum.FontWeight.Regular, Enum.FontStyle.Normal, "Deselected" ) -switchThemeIcon:setCaption("Switch Theme") -switchThemeIcon:align("Right") -switchThemeIcon:setDropdown({ +icon:setCaption("Switch Theme") +icon:setDropdown({ Icon.new() :setLabel("Default") :bindEvent("deselected", function() diff --git a/tests/ToggleInventory.client.luau b/tests/ToggleInventory.client.luau index bed2d44c..4997bc56 100644 --- a/tests/ToggleInventory.client.luau +++ b/tests/ToggleInventory.client.luau @@ -4,8 +4,26 @@ local Icon = require(script.Parent.Satchel.Packages.topbarplus) local Satchel = require(script.Parent.Satchel) local icon = Icon.new() -icon:setLabel("Toggle Inventory") +icon:modifyTheme({ + { "IconLabelContainer", "TargetWidth", 0 }, -- Force minimum width + { "IconLabel", "AutoLocalize", false }, -- Don't translate font icon +}) +icon:setLabel("file-box") icon:align("Right") +icon:setTextSize(24) +icon:setTextFont( + "rbxasset://LuaPackages/Packages/_Index/BuilderIcons/BuilderIcons/BuilderIcons.json", + Enum.FontWeight.Bold, + Enum.FontStyle.Normal, + "Selected" +) +icon:setTextFont( + "rbxasset://LuaPackages/Packages/_Index/BuilderIcons/BuilderIcons/BuilderIcons.json", + Enum.FontWeight.Regular, + Enum.FontStyle.Normal, + "Deselected" +) +icon:setCaption("Toggle Inventory") icon:bindEvent("deselected", function() if Satchel.isInventoryOpen() then Satchel.closeInventory() From cdfa8ce047e89b1d60fcd916123895c104e62415 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Wed, 8 Apr 2026 13:28:43 -0700 Subject: [PATCH 153/186] Add detecting inventory state Signed-off-by: Ryan Luu --- tests/ToggleInventory.client.luau | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/tests/ToggleInventory.client.luau b/tests/ToggleInventory.client.luau index 4997bc56..68a3f4c8 100644 --- a/tests/ToggleInventory.client.luau +++ b/tests/ToggleInventory.client.luau @@ -24,11 +24,21 @@ icon:setTextFont( "Deselected" ) icon:setCaption("Toggle Inventory") -icon:bindEvent("deselected", function() - if Satchel.isInventoryOpen() then - Satchel.closeInventory() - else - Satchel.openInventory() + +icon.toggled:Connect(function(isSelected, fromSource) + if fromSource == "User" then + if isSelected then + Satchel.openInventory() + else + Satchel.closeInventory() + end end end) -icon:oneClick() + +Satchel.inventoryOpened:Connect(function() + icon:select() +end) + +Satchel.inventoryClosed:Connect(function() + icon:deselect() +end) From 8ed3b361acdf77112072d908e7c9d94dd197b908 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Wed, 8 Apr 2026 15:08:19 -0700 Subject: [PATCH 154/186] Add bindable event for theme change Signed-off-by: Ryan Luu --- src/Api/setTheme.luau | 3 +++ src/BindableEvents/ThemeChanged.model.json | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 src/BindableEvents/ThemeChanged.model.json diff --git a/src/Api/setTheme.luau b/src/Api/setTheme.luau index 7ede6ea5..46333de3 100644 --- a/src/Api/setTheme.luau +++ b/src/Api/setTheme.luau @@ -2,6 +2,7 @@ local RunService = game:GetService("RunService") +local bindableEvents = script.Parent.Parent.BindableEvents local styleSheets = script.Parent.Parent.Design local currentTheme = styleSheets.SatchelStyleSheet:FindFirstChildWhichIsA("StyleDerive") @@ -11,6 +12,8 @@ local function setTheme(theme: string | StyleSheet) local newTheme = if typeof(theme) == "string" then styleSheets:WaitForChild(theme) else theme currentTheme.StyleSheet = newTheme + + bindableEvents.ThemeChanged:Fire(newTheme) end return setTheme diff --git a/src/BindableEvents/ThemeChanged.model.json b/src/BindableEvents/ThemeChanged.model.json new file mode 100644 index 00000000..1399ec04 --- /dev/null +++ b/src/BindableEvents/ThemeChanged.model.json @@ -0,0 +1,3 @@ +{ + "ClassName": "BindableEvent" +} \ No newline at end of file From 980c0458812315d8690023dccc6e1aeb33d3fcee Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 9 Apr 2026 08:59:01 -0700 Subject: [PATCH 155/186] Rename HotbarContext.model.json to HotbarContext.model.jsonc Signed-off-by: Ryan Luu --- .../{HotbarContext.model.json => HotbarContext.model.jsonc} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/Bindings/{HotbarContext.model.json => HotbarContext.model.jsonc} (99%) diff --git a/src/Bindings/HotbarContext.model.json b/src/Bindings/HotbarContext.model.jsonc similarity index 99% rename from src/Bindings/HotbarContext.model.json rename to src/Bindings/HotbarContext.model.jsonc index a70243cb..75829ae6 100644 --- a/src/Bindings/HotbarContext.model.json +++ b/src/Bindings/HotbarContext.model.jsonc @@ -174,4 +174,4 @@ ] } ] -} \ No newline at end of file +} From a64a1f411c0e88e179f48fd766dc7e9148e7bf23 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 9 Apr 2026 10:40:42 -0700 Subject: [PATCH 156/186] Remove stories folder and merge into components Signed-off-by: Ryan Luu --- src/{Stories => Components}/App.story.luau | 2 +- src/{Stories => Components}/Backpack.story.luau | 2 +- src/{Stories => Components}/Hotbar.story.luau | 2 +- src/{Stories => Components}/HotbarHint.story.luau | 2 +- src/{Stories => Components}/Inventory.story.luau | 2 +- src/{Stories => Components}/InventoryHint.story.luau | 2 +- src/{Stories => Components}/Satchel.storybook.luau | 0 src/{Stories => Components}/Searchbar.story.luau | 2 +- src/{Stories => Components}/Slot.story.luau | 2 +- src/{Stories => Components}/Tooltip.story.luau | 2 +- 10 files changed, 9 insertions(+), 9 deletions(-) rename src/{Stories => Components}/App.story.luau (93%) rename src/{Stories => Components}/Backpack.story.luau (92%) rename src/{Stories => Components}/Hotbar.story.luau (92%) rename src/{Stories => Components}/HotbarHint.story.luau (81%) rename src/{Stories => Components}/Inventory.story.luau (90%) rename src/{Stories => Components}/InventoryHint.story.luau (85%) rename src/{Stories => Components}/Satchel.storybook.luau (100%) rename src/{Stories => Components}/Searchbar.story.luau (77%) rename src/{Stories => Components}/Slot.story.luau (93%) rename src/{Stories => Components}/Tooltip.story.luau (85%) diff --git a/src/Stories/App.story.luau b/src/Components/App.story.luau similarity index 93% rename from src/Stories/App.story.luau rename to src/Components/App.story.luau index a2e48a63..6ca53a31 100644 --- a/src/Stories/App.story.luau +++ b/src/Components/App.story.luau @@ -2,7 +2,7 @@ local React = require(script.Parent.Parent.Parent.react) -local App = require(script.Parent.Parent.Components.App) +local App = require(script.Parent.App) local controls = { hintVisible = true, diff --git a/src/Stories/Backpack.story.luau b/src/Components/Backpack.story.luau similarity index 92% rename from src/Stories/Backpack.story.luau rename to src/Components/Backpack.story.luau index ee42708e..c9bcd462 100644 --- a/src/Stories/Backpack.story.luau +++ b/src/Components/Backpack.story.luau @@ -2,7 +2,7 @@ local React = require(script.Parent.Parent.Parent.react) -local Backpack = require(script.Parent.Parent.Components.Backpack) +local Backpack = require(script.Parent.Backpack) local controls = { slots = 10, diff --git a/src/Stories/Hotbar.story.luau b/src/Components/Hotbar.story.luau similarity index 92% rename from src/Stories/Hotbar.story.luau rename to src/Components/Hotbar.story.luau index 896e4c59..6b9645db 100644 --- a/src/Stories/Hotbar.story.luau +++ b/src/Components/Hotbar.story.luau @@ -2,7 +2,7 @@ local React = require(script.Parent.Parent.Parent.react) -local Hotbar = require(script.Parent.Parent.Components.Hotbar) +local Hotbar = require(script.Parent.Hotbar) local controls = { slots = 10, diff --git a/src/Stories/HotbarHint.story.luau b/src/Components/HotbarHint.story.luau similarity index 81% rename from src/Stories/HotbarHint.story.luau rename to src/Components/HotbarHint.story.luau index dbb91033..aae63226 100644 --- a/src/Stories/HotbarHint.story.luau +++ b/src/Components/HotbarHint.story.luau @@ -2,7 +2,7 @@ local React = require(script.Parent.Parent.Parent.react) -local HotbarHint = require(script.Parent.Parent.Components.HotbarHint) +local HotbarHint = require(script.Parent.HotbarHint) return { name = "Hotbar Hint", diff --git a/src/Stories/Inventory.story.luau b/src/Components/Inventory.story.luau similarity index 90% rename from src/Stories/Inventory.story.luau rename to src/Components/Inventory.story.luau index e1488622..ba53c6d5 100644 --- a/src/Stories/Inventory.story.luau +++ b/src/Components/Inventory.story.luau @@ -2,7 +2,7 @@ local React = require(script.Parent.Parent.Parent.react) -local Inventory = require(script.Parent.Parent.Components.Inventory) +local Inventory = require(script.Parent.Inventory) local controls = { toolName = "Sword", diff --git a/src/Stories/InventoryHint.story.luau b/src/Components/InventoryHint.story.luau similarity index 85% rename from src/Stories/InventoryHint.story.luau rename to src/Components/InventoryHint.story.luau index 856f4e2e..c4e6c5b7 100644 --- a/src/Stories/InventoryHint.story.luau +++ b/src/Components/InventoryHint.story.luau @@ -2,7 +2,7 @@ local React = require(script.Parent.Parent.Parent.react) -local InventoryHint = require(script.Parent.Parent.Components.InventoryHint) +local InventoryHint = require(script.Parent.InventoryHint) local controls = { text = "Remove from Hotbar", diff --git a/src/Stories/Satchel.storybook.luau b/src/Components/Satchel.storybook.luau similarity index 100% rename from src/Stories/Satchel.storybook.luau rename to src/Components/Satchel.storybook.luau diff --git a/src/Stories/Searchbar.story.luau b/src/Components/Searchbar.story.luau similarity index 77% rename from src/Stories/Searchbar.story.luau rename to src/Components/Searchbar.story.luau index c6d8c327..f2ba6f87 100644 --- a/src/Stories/Searchbar.story.luau +++ b/src/Components/Searchbar.story.luau @@ -2,7 +2,7 @@ local React = require(script.Parent.Parent.Parent.react) -local Searchbar = require(script.Parent.Parent.Components.Searchbar) +local Searchbar = require(script.Parent.Searchbar) return { summary = "Search for items in the inventory", diff --git a/src/Stories/Slot.story.luau b/src/Components/Slot.story.luau similarity index 93% rename from src/Stories/Slot.story.luau rename to src/Components/Slot.story.luau index 66085b47..078e314d 100644 --- a/src/Stories/Slot.story.luau +++ b/src/Components/Slot.story.luau @@ -2,7 +2,7 @@ local React = require(script.Parent.Parent.Parent.react) -local Slot = require(script.Parent.Parent.Components.Slot) +local Slot = require(script.Parent.Slot) local controls = { toolName = "Sword", diff --git a/src/Stories/Tooltip.story.luau b/src/Components/Tooltip.story.luau similarity index 85% rename from src/Stories/Tooltip.story.luau rename to src/Components/Tooltip.story.luau index 6ec7aac5..60d857d3 100644 --- a/src/Stories/Tooltip.story.luau +++ b/src/Components/Tooltip.story.luau @@ -2,7 +2,7 @@ local React = require(script.Parent.Parent.Parent.react) -local Tooltip = require(script.Parent.Parent.Components.Tooltip) +local Tooltip = require(script.Parent.Tooltip) local controls = { text = "I'm a tooltip!", From db1420b61bcd46b0377277701aa5222f5f346b7c Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 9 Apr 2026 11:20:15 -0700 Subject: [PATCH 157/186] Use test project for sourcemap Signed-off-by: Ryan Luu --- .devcontainer/devcontainer.json | 2 +- .vscode/settings.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 6ec304a6..9c108c86 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -40,7 +40,7 @@ }, // Use 'postCreateCommand' to run commands after the container is created. - "postCreateCommand": "pip install mkdocs-material mike --break-system-packages && rokit install --no-trust-check && wally install && rojo sourcemap package.project.json --output sourcemap.json && wally-package-types --sourcemap sourcemap.json Packages/", + "postCreateCommand": "pip install mkdocs-material mike --break-system-packages && rokit install --no-trust-check && wally install && rojo sourcemap test.project.json --output sourcemap.json && wally-package-types --sourcemap sourcemap.json Packages/", // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. "remoteUser": "root" diff --git a/.vscode/settings.json b/.vscode/settings.json index 7bf33192..fde8f0ab 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,5 +11,5 @@ "tag:yaml.org,2002:python/name:pymdownx.superfences.fence_code_format", "tag:yaml.org,2002:python/object/apply:pymdownx.slugs.slugify mapping" ], - "luau-lsp.sourcemap.rojoProjectFile": "package.project.json" + "luau-lsp.sourcemap.rojoProjectFile": "test.project.json" } \ No newline at end of file From a269ac2bb20b61c7209e1695bf27958e5d001aef Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 9 Apr 2026 12:58:28 -0700 Subject: [PATCH 158/186] Cleanup hotbar context Signed-off-by: Ryan Luu --- src/Bindings/HotbarContext.model.json | 47 +++++++ src/Bindings/HotbarContext.model.jsonc | 177 ------------------------- 2 files changed, 47 insertions(+), 177 deletions(-) create mode 100644 src/Bindings/HotbarContext.model.json delete mode 100644 src/Bindings/HotbarContext.model.jsonc diff --git a/src/Bindings/HotbarContext.model.json b/src/Bindings/HotbarContext.model.json new file mode 100644 index 00000000..165abab4 --- /dev/null +++ b/src/Bindings/HotbarContext.model.json @@ -0,0 +1,47 @@ +{ + "ClassName": "InputContext", + "Properties": { + "Priority": 2000 + }, + "Children": [ + { + "Name": "SlotLeftAction", + "ClassName": "InputAction", + "Children": [ + { + "Name": "GamepadBinding", + "ClassName": "InputBinding", + "Properties": { + "KeyCode": "ButtonL1" + } + } + ] + }, + { + "Name": "SlotRightAction", + "ClassName": "InputAction", + "Children": [ + { + "Name": "GamepadBinding", + "ClassName": "InputBinding", + "Properties": { + "KeyCode": "ButtonR1" + } + } + ] + }, + { + "Name": "ToggleInventoryAction", + "ClassName": "InputAction", + "Children": [ + { + "Name": "KeyBinding", + "ClassName": "InputBinding", + "Properties": { + "KeyCode": "Backquote" + } + } + ] + } + ] +} diff --git a/src/Bindings/HotbarContext.model.jsonc b/src/Bindings/HotbarContext.model.jsonc deleted file mode 100644 index 75829ae6..00000000 --- a/src/Bindings/HotbarContext.model.jsonc +++ /dev/null @@ -1,177 +0,0 @@ -{ - "ClassName": "InputContext", - "Properties": { - "Priority": 2000 - }, - "Children": [ - { - "Name": "SlotLeftAction", - "ClassName": "InputAction", - "Children": [ - { - "Name": "GamepadBinding", - "ClassName": "InputBinding", - "Properties": { - "KeyCode": "ButtonL1" - } - } - ] - }, - { - "Name": "SlotRightAction", - "ClassName": "InputAction", - "Children": [ - { - "Name": "GamepadBinding", - "ClassName": "InputBinding", - "Properties": { - "KeyCode": "ButtonR1" - } - } - ] - }, - // { - // "Name": "SlotOneAction", - // "ClassName": "InputAction", - // "Children": [ - // { - // "Name": "KeyBinding", - // "ClassName": "InputBinding", - // "Properties": { - // "KeyCode": "One" - // } - // } - // ] - // }, - // { - // "Name": "SlotTwoAction", - // "ClassName": "InputAction", - // "Children": [ - // { - // "Name": "KeyBinding", - // "ClassName": "InputBinding", - // "Properties": { - // "KeyCode": "Two" - // } - // } - // ] - // }, - // { - // "Name": "SlotThreeAction", - // "ClassName": "InputAction", - // "Children": [ - // { - // "Name": "KeyBinding", - // "ClassName": "InputBinding", - // "Properties": { - // "KeyCode": "Three" - // } - // } - // ] - // }, - // { - // "Name": "SlotFourAction", - // "ClassName": "InputAction", - // "Children": [ - // { - // "Name": "KeyBinding", - // "ClassName": "InputBinding", - // "Properties": { - // "KeyCode": "Four" - // } - // } - // ] - // }, - // { - // "Name": "SlotFiveAction", - // "ClassName": "InputAction", - // "Children": [ - // { - // "Name": "KeyBinding", - // "ClassName": "InputBinding", - // "Properties": { - // "KeyCode": "Five" - // } - // } - // ] - // }, - // { - // "Name": "SlotSixAction", - // "ClassName": "InputAction", - // "Children": [ - // { - // "Name": "KeyBinding", - // "ClassName": "InputBinding", - // "Properties": { - // "KeyCode": "Six" - // } - // } - // ] - // }, - // { - // "Name": "SlotSevenAction", - // "ClassName": "InputAction", - // "Children": [ - // { - // "Name": "KeyBinding", - // "ClassName": "InputBinding", - // "Properties": { - // "KeyCode": "Seven" - // } - // } - // ] - // }, - // { - // "Name": "SlotEightAction", - // "ClassName": "InputAction", - // "Children": [ - // { - // "Name": "KeyBinding", - // "ClassName": "InputBinding", - // "Properties": { - // "KeyCode": "Eight" - // } - // } - // ] - // }, - // { - // "Name": "SlotNineAction", - // "ClassName": "InputAction", - // "Children": [ - // { - // "Name": "KeyBinding", - // "ClassName": "InputBinding", - // "Properties": { - // "KeyCode": "Nine" - // } - // } - // ] - // }, - // { - // "Name": "SlotZeroAction", - // "ClassName": "InputAction", - // "Children": [ - // { - // "Name": "KeyBinding", - // "ClassName": "InputBinding", - // "Properties": { - // "KeyCode": "Zero" - // } - // } - // ] - // }, - { - "Name": "ToggleInventoryAction", - "ClassName": "InputAction", - "Children": [ - { - "Name": "KeyBinding", - "ClassName": "InputBinding", - "Properties": { - "KeyCode": "Backquote" - } - } - ] - } - ] -} From b2105ac5fb1c723ae1305e5642a658cf0375cc34 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 9 Apr 2026 13:30:29 -0700 Subject: [PATCH 159/186] Use StyleQuery for showing hints Signed-off-by: Ryan Luu --- src/Components/App.luau | 15 +++ src/Components/HotbarHint.luau | 30 +----- src/Components/InventoryHint.luau | 27 +---- src/Design.rbxmx | 167 ++++++++++++++++++------------ 4 files changed, 117 insertions(+), 122 deletions(-) diff --git a/src/Components/App.luau b/src/Components/App.luau index 40cc2c87..508da540 100644 --- a/src/Components/App.luau +++ b/src/Components/App.luau @@ -26,6 +26,19 @@ export type Props = { local function App(props: Props) local backpackSize, setBackpackSize = React.useState(Vector2.zero) + local slotCount = props.slots or 10 + + local hotbarVisible = props.opened or false + + -- Don't show hotbar hints if hotbar has no slots + if not hotbarVisible and props.items then + for order = 1, slotCount do + if props.items[order] ~= nil then + hotbarVisible = true + break + end + end + end return React.createElement("Frame", { [React.Tag] = "HotbarHints", @@ -34,11 +47,13 @@ local function App(props: Props) keyCode = SlotLeftGamepadKeyCode, forceVisible = props.forceGamepadHintVisible, order = -1, + visible = hotbarVisible, }), SlotRightHint = React.createElement(HotbarHint, { keyCode = SlotRightGamepadKeyCode, forceVisible = props.forceGamepadHintVisible, order = 1, + visible = hotbarVisible, }), InventoryHints = React.createElement("Frame", { Size = UDim2.fromOffset(backpackSize.X, 0), diff --git a/src/Components/HotbarHint.luau b/src/Components/HotbarHint.luau index 46cc5c24..681892c6 100644 --- a/src/Components/HotbarHint.luau +++ b/src/Components/HotbarHint.luau @@ -8,38 +8,14 @@ export type Props = { keyCode: Enum.KeyCode, forceVisible: boolean?, order: number?, + visible: boolean?, } local function HotbarHint(props: Props) - -- Only show hint if gamepad is preferred or forced visible - local isGamepadPreferred, setIsGamepadPreferred = - React.useState(UserInputService.PreferredInput == Enum.PreferredInput.Gamepad) - - React.useEffect(function() - local function preferredInputChanged() - local preferredInput = UserInputService.PreferredInput - - if preferredInput == Enum.PreferredInput.Gamepad then - setIsGamepadPreferred(true) - else - setIsGamepadPreferred(false) - end - end - - -- preferredInputChanged() - local signal = UserInputService:GetPropertyChangedSignal("PreferredInput"):Connect(preferredInputChanged) - - return function() - signal:Disconnect() - end - end, {}) - - local visible = props.forceVisible or isGamepadPreferred - return React.createElement("Frame", { LayoutOrder = props.order, - Visible = visible, - [React.Tag] = "HotbarHint", + Visible = props.forceVisible, + [React.Tag] = if props.visible then "HotbarHint" else nil, }, { KeyCode = React.createElement("ImageLabel", { Image = UserInputService:GetImageForKeyCode(props.keyCode), diff --git a/src/Components/InventoryHint.luau b/src/Components/InventoryHint.luau index da314b51..cc10c762 100644 --- a/src/Components/InventoryHint.luau +++ b/src/Components/InventoryHint.luau @@ -12,34 +12,9 @@ export type Props = { } local function InventoryHint(props: Props) - -- Only show hint if gamepad is preferred or forced visible - local isGamepadPreferred, setIsGamepadPreferred = - React.useState(UserInputService.PreferredInput == Enum.PreferredInput.Gamepad) - - React.useEffect(function() - local function preferredInputChanged() - local preferredInput = UserInputService.PreferredInput - - if preferredInput == Enum.PreferredInput.Gamepad then - setIsGamepadPreferred(true) - else - setIsGamepadPreferred(false) - end - end - - -- preferredInputChanged() - local signal = UserInputService:GetPropertyChangedSignal("PreferredInput"):Connect(preferredInputChanged) - - return function() - signal:Disconnect() - end - end, {}) - - local visible = props.forceVisible or isGamepadPreferred - return React.createElement("Frame", { LayoutOrder = props.order, - Visible = visible, + Visible = props.forceVisible, [React.Tag] = "InventoryHint", }, { KeyCode = React.createElement("ImageLabel", { diff --git a/src/Design.rbxmx b/src/Design.rbxmx index c7c7f4dd..095629f3 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,7 +11,7 @@ -1 - + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= 0 @@ -20,10 +20,10 @@ -1 - + 0 - RBX82ABF0CF469E40EAAC93D8D654ECF2FC + RBXA0A437E0DB294299BD65D7A3EB3819DA 0 false @@ -33,7 +33,7 @@ - + -1 - + 0 - RBX82ABF0CF469E40EAAC93D8D654ECF2FC + RBXA0A437E0DB294299BD65D7A3EB3819DA 0 false @@ -68,7 +68,7 @@ bmRDb2xvcg/NzMw+zczMPs3MzD4OAAAAVG9vbFRpcFBhZGRpbmcJAAAAAAIAAAA=]]> - + 0 @@ -77,11 +77,11 @@ bmRDb2xvcg/NzMw+zczMPs3MzD4OAAAAVG9vbFRpcFBhZGRpbmcJAAAAAAIAAAA=]]>-1 - + 0 - + .HotbarHint @@ -91,7 +91,7 @@ AAAAAAAAPAAAAA==]]> -1 - + 0 -1 - + 0 AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== @@ -121,8 +121,22 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAA==]]> + + + 1 + AQAAAAcAAABWaXNpYmxlAwE= + + @PreferredInputGamepad + + 0 + false + @PreferredInputGamepad + -1 + + + - + 0 -1 - + 0 - + 0 - RBXA22B2273A3C846D8AF69CE842BE99BBB + RBX19AA82FA7C1746B08CBD95BAC7FBB3D4 0 false @@ -166,11 +180,12 @@ YXBzAwE=]]> - + 0 - + .InventoryHint @@ -180,7 +195,7 @@ dW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/BAAAAFNpemUKAAAAAAAAAAAAAAAAKAAAAA==]]>-1 - + 0 -1 - + 0 AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== @@ -210,7 +225,7 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAAAAACUAAAAAAAAAJQAAAA==]]> - + 0 + + + 1 + AQAAAAcAAABWaXNpYmxlAwE= + + @PreferredInputGamepad + + 0 + false + @PreferredInputGamepad + -1 + + + - + 0 -1 - + 0 - + 0 -1 - + 0 - + 0 - + 0 -1 - + 0 AAAAAA== @@ -345,7 +374,7 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAA==]]> - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= @@ -360,7 +389,7 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAA==]]> - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz @@ -390,7 +419,7 @@ AIA/AAAAAAAAAAAAAAAA]]> - + 0 -1 - + 0 - + 0 - + 0 AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA @@ -456,7 +485,7 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkU3VyZmFjZVBhZGRpbmc=]]> - + 0 -1 - + 0 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz @@ -506,7 +535,7 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkVG9vbFRpcFBhZGRpbmc=]]> - + 0 -1 - + 0 AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= @@ -534,7 +563,7 @@ dW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/CwAAAExheW91dE9yZGVyBgAAAAAAAPA/]]> - + 0 - + 0 -1 - + 0 AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= @@ -580,7 +609,7 @@ dW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/]]> - + 0 -1 - + 0 AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= @@ -609,7 +638,7 @@ ABYAAABCYWNrZ3JvdW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/]]> - + 0 -1 - + 0 - + 0 AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= @@ -656,7 +685,7 @@ AAAAAAAoQA==]]> -1 - + 0 - + 0 AQAAAAcAAABWaXNpYmxlAwA= @@ -691,7 +720,7 @@ AAAAVGV4dFlBbGlnbm1lbnQVDgAAAFRleHRZQWxpZ25tZW50AAAAAA==]]> - + 0 - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== @@ -736,7 +765,7 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> - + 0 AAAAAA== @@ -749,7 +778,7 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> -1 - + 0 - + 0 -1 - + 0 AAAAAA== @@ -794,7 +823,7 @@ chYAAABCYWNrZ3JvdW5kVHJhbnNwYXJlbmN5BgAAAAAAAAAA]]> -1 - + 0 - + 0 AAAAAA== @@ -825,7 +854,7 @@ cgIVAAAAJFNsb3RQcmVzc1N0cm9rZUNvbG9yCQAAAFRoaWNrbmVzcwYAAAAAAAAAQA==]]>-1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -840,7 +869,7 @@ cgIVAAAAJFNsb3RQcmVzc1N0cm9rZUNvbG9yCQAAAFRoaWNrbmVzcwYAAAAAAAAAQA==]]> - + 0 AAAAAA== @@ -853,7 +882,7 @@ cgIVAAAAJFNsb3RQcmVzc1N0cm9rZUNvbG9yCQAAAFRoaWNrbmVzcwYAAAAAAAAAQA==]]>-1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -868,7 +897,7 @@ cgIVAAAAJFNsb3RQcmVzc1N0cm9rZUNvbG9yCQAAAFRoaWNrbmVzcwYAAAAAAAAAQA==]]> - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz @@ -884,7 +913,7 @@ cgIVAAAAJFNsb3RQcmVzc1N0cm9rZUNvbG9yCQAAAFRoaWNrbmVzcwYAAAAAAAAAQA==]]> - + -1 - + 0 - RBXABAC9F6B0A0A436FAEEA9B173F750FB4 + RBXDA581B23707D4C7D83A751D1FB1C46A9 0 false @@ -938,7 +967,7 @@ VGV4dFNpemU=]]> - + Date: Thu, 9 Apr 2026 14:15:30 -0700 Subject: [PATCH 160/186] Fix styling Signed-off-by: Ryan Luu --- src/Design.rbxmx | 488 ++++++++++++++++++++++++----------------------- 1 file changed, 251 insertions(+), 237 deletions(-) diff --git a/src/Design.rbxmx b/src/Design.rbxmx index 095629f3..e3fa022b 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,7 +11,23 @@ -1 - + + + + 0 + false + ThemeTokens + -1 + + + + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= 0 @@ -20,10 +36,10 @@ -1 - + 0 - RBXA0A437E0DB294299BD65D7A3EB3819DA + RBXB86CE5B111EA4B6CB3012A38E1F0D818 0 false @@ -33,7 +49,7 @@ - + -1 - + 0 - RBXA0A437E0DB294299BD65D7A3EB3819DA + RBXB86CE5B111EA4B6CB3012A38E1F0D818 0 false @@ -68,7 +84,7 @@ bmRDb2xvcg/NzMw+zczMPs3MzD4OAAAAVG9vbFRpcFBhZGRpbmcJAAAAAAIAAAA=]]> - + 0 @@ -77,7 +93,7 @@ bmRDb2xvcg/NzMw+zczMPs3MzD4OAAAAVG9vbFRpcFBhZGRpbmcJAAAAAAIAAAA=]]>-1 - + 0 -1 - + 0 -1 - + 0 AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== @@ -121,9 +137,9 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAA==]]> - + - 1 + 0 AQAAAAcAAABWaXNpYmxlAwE= @PreferredInputGamepad @@ -136,51 +152,7 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAA==]]> - - - 0 - - - .Hints - - 0 - false - .Hints - -1 - - - - - 0 - - - ::UIListLayout - - 0 - false - ::UIListLayout - -1 - - - - - - - 0 - RBX19AA82FA7C1746B08CBD95BAC7FBB3D4 - - 0 - false - Derive from DefaultTheme - -1 - - - - + 0 -1 - + 0 -1 - + 0 AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== @@ -225,7 +197,7 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAAAAACUAAAAAAAAAJQAAAA==]]> - + 0 - + - 1 + 0 AQAAAAcAAABWaXNpYmxlAwE= @PreferredInputGamepad @@ -258,7 +230,19 @@ VGV4dFNpemU=]]> - + + + 0 + RBX888462ECA72C4ACB8B0AF5B10CCFAADF + + 0 + false + Derive from DefaultTheme + -1 + + + + 0 -1 - + 0 - + 0 -1 - + 0 - + 0 - + + + 0 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= + + ::UICorner + + 0 + false + ::UICorner + -1 + + + + 0 -1 - + 0 AAAAAA== @@ -374,22 +372,8 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAA==]]> - - - 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz @@ -419,7 +403,37 @@ AIA/AAAAAAAAAAAAAAAA]]> - + + + 0 + + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + + + + 0 + AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + + 0 -1 - + 0 - - - 0 - - - ::UIPadding - - 0 - false - ::UIPadding - -1 - - - - - - 0 - AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA - - ::UIListLayout - - 0 - false - ::UIListLayout - -1 - - - - + 0 -1 - + 0 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz @@ -535,7 +519,7 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkVG9vbFRpcFBhZGRpbmc=]]> - + 0 -1 - + 0 AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= @@ -563,7 +547,7 @@ dW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/CwAAAExheW91dE9yZGVyBgAAAAAAAPA/]]> - + 0 - + 0 -1 - + 0 AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= @@ -609,7 +593,7 @@ dW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/]]> - + 0 -1 - + 0 AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= @@ -638,7 +622,7 @@ ABYAAABCYWNrZ3JvdW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/]]> - + 0 -1 - + 0 - - - 0 - AQAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAA= - - >TextLabel - - 0 - false - >TextLabel - -1 - - - - - 0 - - - .SlotNumber - - 0 - false - .SlotNumber - -1 - - - - - - 0 - AQAAAAcAAABWaXNpYmxlAwA= - - .Tooltip - - 0 - false - .Tooltip - -1 - - - - - + 0 - - - 0 - - - >ImageLabel - - 0 - false - >ImageLabel - -1 - - - - - 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - - + 0 AAAAAA== @@ -778,7 +685,7 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> -1 - + 0 - + 0 -1 - + 0 AAAAAA== @@ -823,7 +730,7 @@ chYAAABCYWNrZ3JvdW5kVHJhbnNwYXJlbmN5BgAAAAAAAAAA]]> -1 - + 0 - + 0 AAAAAA== @@ -854,7 +761,7 @@ cgIVAAAAJFNsb3RQcmVzc1N0cm9rZUNvbG9yCQAAAFRoaWNrbmVzcwYAAAAAAAAAQA==]]>-1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -869,7 +776,7 @@ cgIVAAAAJFNsb3RQcmVzc1N0cm9rZUNvbG9yCQAAAFRoaWNrbmVzcwYAAAAAAAAAQA==]]> - + 0 AAAAAA== @@ -882,7 +789,7 @@ cgIVAAAAJFNsb3RQcmVzc1N0cm9rZUNvbG9yCQAAAFRoaWNrbmVzcwYAAAAAAAAAQA==]]>-1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -897,7 +804,7 @@ cgIVAAAAJFNsb3RQcmVzc1N0cm9rZUNvbG9yCQAAAFRoaWNrbmVzcwYAAAAAAAAAQA==]]> - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz @@ -911,9 +818,132 @@ cgIVAAAAJFNsb3RQcmVzc1N0cm9rZUNvbG9yCQAAAFRoaWNrbmVzcwYAAAAAAAAAQA==]]> + + + 0 + + + >ImageLabel + + 0 + false + >ImageLabel + -1 + + + + + 0 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== + + ::UICorner + + 0 + false + ::UICorner + -1 + + + + + + + 0 + AgAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAAHAAAAVmlzaWJsZQMA + + >TextLabel + + 0 + false + >TextLabel + -1 + + + + + 0 + AQAAAAcAAABWaXNpYmxlAwA= + + .Tooltip + + 0 + false + .Tooltip + -1 + + + + + + 0 + + + .SlotNumber + + 0 + false + .SlotNumber + -1 + + + + + 0 + AQAAAAcAAABWaXNpYmxlAwE= + + @PreferredInputKeyboardAndMouse + + 0 + false + @PreferredInputKeyboardAndMouse + -1 + + + + + + + + + 0 + + + .Hints + + 0 + false + .Hints + -1 + + + + + 0 + + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + - + -1 - + 0 - RBXDA581B23707D4C7D83A751D1FB1C46A9 + RBX58C39F64B8D947F1B579177318A372BB 0 false @@ -967,21 +997,5 @@ VGV4dFNpemU=]]> - - - - 0 - false - ThemeTokens - -1 - - - \ No newline at end of file From fe9a9d5795c8d6fdf6867aa36b8dd11085fbdd6f Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 9 Apr 2026 14:36:27 -0700 Subject: [PATCH 161/186] Update debug icons Signed-off-by: Ryan Luu --- src/init.luau | 1 + tests/CoreGuiBackpack.client.luau | 13 ------------- tests/SatchelEnabled.client.luau | 30 ++++++++++++++++++++++++++++++ tests/ToggleSatchel.client.luau | 12 ------------ 4 files changed, 31 insertions(+), 25 deletions(-) delete mode 100644 tests/CoreGuiBackpack.client.luau create mode 100644 tests/SatchelEnabled.client.luau delete mode 100644 tests/ToggleSatchel.client.luau diff --git a/src/init.luau b/src/init.luau index 75559cb7..70da5fa3 100644 --- a/src/init.luau +++ b/src/init.luau @@ -20,4 +20,5 @@ return { backpackItemUnequipped = bindableEvents.BackpackItemUnequipped.Event, inventoryOpened = bindableEvents.InventoryOpened.Event, inventoryClosed = bindableEvents.InventoryClosed.Event, + themeChanged = bindableEvents.ThemeChanged.Event, } diff --git a/tests/CoreGuiBackpack.client.luau b/tests/CoreGuiBackpack.client.luau deleted file mode 100644 index 9cac6f9b..00000000 --- a/tests/CoreGuiBackpack.client.luau +++ /dev/null @@ -1,13 +0,0 @@ ---!strict - -local StarterGui = game:GetService("StarterGui") - -local Icon = require(script.Parent.Satchel.Packages.topbarplus) - -local icon = Icon.new() -icon:setLabel("Toggle CoreGui Backpack") -icon:align("Right") -icon:bindEvent("deselected", function() - StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, not StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Backpack)) -end) -icon:oneClick() diff --git a/tests/SatchelEnabled.client.luau b/tests/SatchelEnabled.client.luau new file mode 100644 index 00000000..cbd74226 --- /dev/null +++ b/tests/SatchelEnabled.client.luau @@ -0,0 +1,30 @@ +--!strict + +local Icon = require(script.Parent.Satchel.Packages.topbarplus) +local Satchel = require(script.Parent.Satchel) + +local icon = Icon.new() +icon:modifyTheme({ + { "IconLabelContainer", "TargetWidth", 0 }, -- Force minimum width + { "IconLabel", "AutoLocalize", false }, -- Don't translate font icon +}) +icon:setLabel("globe-simplified") +icon:align("Right") +icon:setTextSize(24) +icon:setTextFont( + "rbxasset://LuaPackages/Packages/_Index/BuilderIcons/BuilderIcons/BuilderIcons.json", + Enum.FontWeight.Bold, + Enum.FontStyle.Normal, + "Deselected" +) +icon:setTextFont( + "rbxasset://LuaPackages/Packages/_Index/BuilderIcons/BuilderIcons/BuilderIcons.json", + Enum.FontWeight.Regular, + Enum.FontStyle.Normal, + "Selected" +) +icon:setCaption("Toggle Satchel Enabled") + +icon.toggled:Connect(function() + Satchel.setEnabled(not Satchel.getEnabled()) +end) diff --git a/tests/ToggleSatchel.client.luau b/tests/ToggleSatchel.client.luau deleted file mode 100644 index f4046dd1..00000000 --- a/tests/ToggleSatchel.client.luau +++ /dev/null @@ -1,12 +0,0 @@ ---!strict - -local Icon = require(script.Parent.Satchel.Packages.topbarplus) -local Satchel = require(script.Parent.Satchel) - -local icon = Icon.new() -icon:setLabel("Toggle Satchel") -icon:align("Right") -icon:bindEvent("deselected", function() - Satchel.setEnabled(not Satchel.getEnabled()) -end) -icon:oneClick() From 27e1155a80d1b5af5f83ff03713a3de057b9b39a Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 9 Apr 2026 14:38:03 -0700 Subject: [PATCH 162/186] Update icons Signed-off-by: Ryan Luu --- tests/SatchelEnabled.client.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/SatchelEnabled.client.luau b/tests/SatchelEnabled.client.luau index cbd74226..556d088a 100644 --- a/tests/SatchelEnabled.client.luau +++ b/tests/SatchelEnabled.client.luau @@ -8,7 +8,7 @@ icon:modifyTheme({ { "IconLabelContainer", "TargetWidth", 0 }, -- Force minimum width { "IconLabel", "AutoLocalize", false }, -- Don't translate font icon }) -icon:setLabel("globe-simplified") +icon:setLabel("two-switches-horizontal") icon:align("Right") icon:setTextSize(24) icon:setTextFont( From 79561760812c18df65399569f7e9cc956d084c43 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 9 Apr 2026 14:38:39 -0700 Subject: [PATCH 163/186] Shorten caption Signed-off-by: Ryan Luu --- tests/SatchelEnabled.client.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/SatchelEnabled.client.luau b/tests/SatchelEnabled.client.luau index 556d088a..44e62493 100644 --- a/tests/SatchelEnabled.client.luau +++ b/tests/SatchelEnabled.client.luau @@ -23,7 +23,7 @@ icon:setTextFont( Enum.FontStyle.Normal, "Selected" ) -icon:setCaption("Toggle Satchel Enabled") +icon:setCaption("Satchel Enabled") icon.toggled:Connect(function() Satchel.setEnabled(not Satchel.getEnabled()) From 6eccf4c09b3726b3084d5922b733736f77e3575d Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 9 Apr 2026 16:43:30 -0700 Subject: [PATCH 164/186] Use effect for closing backpack on click out Signed-off-by: Ryan Luu --- src/Client.client.luau | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/Client.client.luau b/src/Client.client.luau index f7909b34..93dd9f7c 100644 --- a/src/Client.client.luau +++ b/src/Client.client.luau @@ -50,14 +50,20 @@ local function Satchel() end, {}) -- Close backpack when clicking outside of it - UserInputService.InputBegan:Connect(function(input: InputObject, gameProcessedEvent: boolean) - local inputType = input.UserInputType - if not gameProcessedEvent then - if inputType == Enum.UserInputType.MouseButton1 or inputType == Enum.UserInputType.Touch then - closeInventory() + React.useEffect(function() + local inputSignal = UserInputService.InputBegan:Connect(function(input, gameProcessedEvent) + local inputType = input.UserInputType + if not gameProcessedEvent then + if inputType == Enum.UserInputType.MouseButton1 or inputType == Enum.UserInputType.Touch then + closeInventory() + end end + end) + + return function() + inputSignal:Disconnect() end - end) + end, {}) -- Change slots based on viewport display size local slots, setSlots = React.useState(10) From c84664f32aafcb78bbae5bea85838fa7082fe3f9 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 9 Apr 2026 17:34:28 -0700 Subject: [PATCH 165/186] Remove inventory toggle Signed-off-by: Ryan Luu --- tests/ToggleInventory.client.luau | 44 ------------------------------- 1 file changed, 44 deletions(-) delete mode 100644 tests/ToggleInventory.client.luau diff --git a/tests/ToggleInventory.client.luau b/tests/ToggleInventory.client.luau deleted file mode 100644 index 68a3f4c8..00000000 --- a/tests/ToggleInventory.client.luau +++ /dev/null @@ -1,44 +0,0 @@ ---!strict - -local Icon = require(script.Parent.Satchel.Packages.topbarplus) -local Satchel = require(script.Parent.Satchel) - -local icon = Icon.new() -icon:modifyTheme({ - { "IconLabelContainer", "TargetWidth", 0 }, -- Force minimum width - { "IconLabel", "AutoLocalize", false }, -- Don't translate font icon -}) -icon:setLabel("file-box") -icon:align("Right") -icon:setTextSize(24) -icon:setTextFont( - "rbxasset://LuaPackages/Packages/_Index/BuilderIcons/BuilderIcons/BuilderIcons.json", - Enum.FontWeight.Bold, - Enum.FontStyle.Normal, - "Selected" -) -icon:setTextFont( - "rbxasset://LuaPackages/Packages/_Index/BuilderIcons/BuilderIcons/BuilderIcons.json", - Enum.FontWeight.Regular, - Enum.FontStyle.Normal, - "Deselected" -) -icon:setCaption("Toggle Inventory") - -icon.toggled:Connect(function(isSelected, fromSource) - if fromSource == "User" then - if isSelected then - Satchel.openInventory() - else - Satchel.closeInventory() - end - end -end) - -Satchel.inventoryOpened:Connect(function() - icon:select() -end) - -Satchel.inventoryClosed:Connect(function() - icon:deselect() -end) From 0a2a0be2e1dc9599b93c2c278eb8b512e7fe50e1 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 9 Apr 2026 17:34:41 -0700 Subject: [PATCH 166/186] Improve state Signed-off-by: Ryan Luu --- tests/SatchelEnabled.client.luau | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/SatchelEnabled.client.luau b/tests/SatchelEnabled.client.luau index 44e62493..e6685697 100644 --- a/tests/SatchelEnabled.client.luau +++ b/tests/SatchelEnabled.client.luau @@ -8,6 +8,7 @@ icon:modifyTheme({ { "IconLabelContainer", "TargetWidth", 0 }, -- Force minimum width { "IconLabel", "AutoLocalize", false }, -- Don't translate font icon }) +icon:select() icon:setLabel("two-switches-horizontal") icon:align("Right") icon:setTextSize(24) @@ -15,16 +16,18 @@ icon:setTextFont( "rbxasset://LuaPackages/Packages/_Index/BuilderIcons/BuilderIcons/BuilderIcons.json", Enum.FontWeight.Bold, Enum.FontStyle.Normal, - "Deselected" + "Selected" ) icon:setTextFont( "rbxasset://LuaPackages/Packages/_Index/BuilderIcons/BuilderIcons/BuilderIcons.json", Enum.FontWeight.Regular, Enum.FontStyle.Normal, - "Selected" + "Deselected" ) +icon:autoDeselect(false) icon:setCaption("Satchel Enabled") - -icon.toggled:Connect(function() - Satchel.setEnabled(not Satchel.getEnabled()) +icon.toggled:Connect(function(isSelected, fromSource) + if fromSource == "User" then + Satchel.setEnabled(isSelected) + end end) From ad537950defed0d3b9690deb3e6d1c5399359c97 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 9 Apr 2026 17:42:22 -0700 Subject: [PATCH 167/186] Improve enabled logic Signed-off-by: Ryan Luu --- src/CoreGuiWarn.client.luau | 2 +- tests/SatchelEnabled.client.luau | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/CoreGuiWarn.client.luau b/src/CoreGuiWarn.client.luau index 9dfce1df..29b8e3cd 100644 --- a/src/CoreGuiWarn.client.luau +++ b/src/CoreGuiWarn.client.luau @@ -5,7 +5,7 @@ local Satchel = require(script.Parent) task.spawn(function() while task.wait(1) do - if StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Backpack) then + if StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Backpack) and Satchel.getEnabled() then warn("[Satchel] CoreGui backpack detected. Disabling Satchel to prevent conflicts.") Satchel.setEnabled(false) break diff --git a/tests/SatchelEnabled.client.luau b/tests/SatchelEnabled.client.luau index e6685697..66ed946e 100644 --- a/tests/SatchelEnabled.client.luau +++ b/tests/SatchelEnabled.client.luau @@ -1,5 +1,7 @@ --!strict +local StarterGui = game:GetService("StarterGui") + local Icon = require(script.Parent.Satchel.Packages.topbarplus) local Satchel = require(script.Parent.Satchel) @@ -25,9 +27,10 @@ icon:setTextFont( "Deselected" ) icon:autoDeselect(false) -icon:setCaption("Satchel Enabled") +icon:setCaption("Toggle Satchel") icon.toggled:Connect(function(isSelected, fromSource) if fromSource == "User" then Satchel.setEnabled(isSelected) + StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, not isSelected) end end) From 6712d68a8cfb615d43cedb19141ad1988144d984 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 9 Apr 2026 17:51:35 -0700 Subject: [PATCH 168/186] Improve deselect logic Signed-off-by: Ryan Luu --- tests/SwitchTheme.client.luau | 53 ++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/tests/SwitchTheme.client.luau b/tests/SwitchTheme.client.luau index ec039aa7..1d3e8ca0 100644 --- a/tests/SwitchTheme.client.luau +++ b/tests/SwitchTheme.client.luau @@ -23,18 +23,43 @@ icon:setTextFont( Enum.FontStyle.Normal, "Deselected" ) +icon:autoDeselect(false) icon:setCaption("Switch Theme") -icon:setDropdown({ - Icon.new() - :setLabel("Default") - :bindEvent("deselected", function() - Satchel.setTheme("DefaultTheme") - end) - :oneClick(), - Icon.new() - :setLabel("Legacy") - :bindEvent("deselected", function() - Satchel.setTheme("LegacyTheme") - end) - :oneClick(), -}) + +local defaultTheme: Icon.Icon +local legacyTheme: Icon.Icon + +defaultTheme = Icon.new() +defaultTheme:select() +defaultTheme:setLabel("Default") +defaultTheme:bindEvent("selected", function() + Satchel.setTheme("DefaultTheme") +end) +defaultTheme:bindEvent("deselected", function() + if not legacyTheme.isSelected then + defaultTheme:select() + Satchel.setTheme("DefaultTheme") + end +end) + +legacyTheme = Icon.new() +legacyTheme:setLabel("Legacy") +legacyTheme:bindEvent("selected", function() + Satchel.setTheme("LegacyTheme") +end) +legacyTheme:bindEvent("deselected", function() + if not defaultTheme.isSelected then + defaultTheme:select() + Satchel.setTheme("DefaultTheme") + end +end) + +icon:setDropdown({ defaultTheme, legacyTheme }) + +Satchel.themeChanged:Connect(function(theme) + if theme.Name == "DefaultTheme" then + defaultTheme:select() + elseif theme.Name == "LegacyTheme" then + legacyTheme:select() + end +end) From 03bf610873fd438f06c3621e73b437a0e118753d Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 9 Apr 2026 18:19:09 -0700 Subject: [PATCH 169/186] Remove ignore instances Signed-off-by: Ryan Luu --- test.project.json | 1 - 1 file changed, 1 deletion(-) diff --git a/test.project.json b/test.project.json index 32cff523..98f301b8 100644 --- a/test.project.json +++ b/test.project.json @@ -5,7 +5,6 @@ "$className": "DataModel", "ReplicatedStorage": { "$className": "ReplicatedStorage", - "$ignoreUnknownInstances": true, "$path": "tests", "Satchel": { "$path": "models/Satchel" From e2746593ffd1bc554ab4b2907b34ee997b743bb1 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 9 Apr 2026 18:29:54 -0700 Subject: [PATCH 170/186] Fix Dev Mode Signed-off-by: Ryan Luu --- src/Client.client.luau | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Client.client.luau b/src/Client.client.luau index 93dd9f7c..6adcf03d 100644 --- a/src/Client.client.luau +++ b/src/Client.client.luau @@ -2,9 +2,13 @@ local GuiService = game:GetService("GuiService") local Players = game:GetService("Players") +local RunService = game:GetService("RunService") local StarterGui = game:GetService("StarterGui") local UserInputService = game:GetService("UserInputService") +-- selene: allow(global_usage) +_G.__DEV__ = RunService:IsStudio() + local React = require(script.Parent.Parent.react) local ReactRoblox = require(script.Parent.Parent["react-roblox"]) local closeInventory = require(script.Parent.Api.closeInventory) From 5e5144c95128dd5f70b207a594d1abc5befbcf8c Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 9 Apr 2026 19:05:38 -0700 Subject: [PATCH 171/186] Remove old dev mode Signed-off-by: Ryan Luu --- tests/DevMode.client.luau | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 tests/DevMode.client.luau diff --git a/tests/DevMode.client.luau b/tests/DevMode.client.luau deleted file mode 100644 index 22167038..00000000 --- a/tests/DevMode.client.luau +++ /dev/null @@ -1,3 +0,0 @@ -local RunService = game:GetService("RunService") - -_G.__DEV__ = RunService:IsStudio() From 20859eb668479d1b08647799372ed3ce1d57cba8 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 9 Apr 2026 19:15:31 -0700 Subject: [PATCH 172/186] Only print attribution on client Signed-off-by: Ryan Luu --- src/Attribution.client.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Attribution.client.luau b/src/Attribution.client.luau index 296bc68b..41ee5989 100644 --- a/src/Attribution.client.luau +++ b/src/Attribution.client.luau @@ -24,7 +24,7 @@ local RunService = game:GetService("RunService") local VERSION = "2.0.0" -- Print attribution. Do not modify without reading above -if not RunService:IsStudio() then +if not RunService:IsStudio() and RunService:IsClient() then print(`💼 Running Satchel v{VERSION} by @WinnersTakesAll`) end From 67ac155c9ba16bcf8d657e3116eb4bfc3d5f5b0f Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 9 Apr 2026 19:33:05 -0700 Subject: [PATCH 173/186] Remove user input detection for slot hints Signed-off-by: Ryan Luu --- src/Components/HotbarHint.luau | 6 ++++-- src/Components/Slot.luau | 27 +-------------------------- 2 files changed, 5 insertions(+), 28 deletions(-) diff --git a/src/Components/HotbarHint.luau b/src/Components/HotbarHint.luau index 681892c6..24308229 100644 --- a/src/Components/HotbarHint.luau +++ b/src/Components/HotbarHint.luau @@ -12,10 +12,12 @@ export type Props = { } local function HotbarHint(props: Props) + local visible = props.visible and props.forceVisible + return React.createElement("Frame", { LayoutOrder = props.order, - Visible = props.forceVisible, - [React.Tag] = if props.visible then "HotbarHint" else nil, + Visible = visible, + [React.Tag] = "HotbarHint", }, { KeyCode = React.createElement("ImageLabel", { Image = UserInputService:GetImageForKeyCode(props.keyCode), diff --git a/src/Components/Slot.luau b/src/Components/Slot.luau index 93a0c4ce..ea19b996 100644 --- a/src/Components/Slot.luau +++ b/src/Components/Slot.luau @@ -1,7 +1,5 @@ --!strict -local UserInputService = game:GetService("UserInputService") - local React = require(script.Parent.Parent.Parent.react) local Tooltip = require(script.Parent.Tooltip) @@ -32,30 +30,7 @@ local function Slot(props: Props) slotNumber = "0" end - -- Only show slot number if keyboard and mouse is preferred or forced visible - local isKeyboardPreferred, setIsKeyboardPreferred = - React.useState(UserInputService.PreferredInput == Enum.PreferredInput.KeyboardAndMouse) - - React.useEffect(function() - local function preferredInputChanged() - local preferredInput = UserInputService.PreferredInput - - if preferredInput == Enum.PreferredInput.KeyboardAndMouse then - setIsKeyboardPreferred(true) - else - setIsKeyboardPreferred(false) - end - end - - -- preferredInputChanged() - local signal = UserInputService:GetPropertyChangedSignal("PreferredInput"):Connect(preferredInputChanged) - - return function() - signal:Disconnect() - end - end, {}) - - local hintVisible = props.hint == true and (props.forceHintVisible or isKeyboardPreferred) + local hintVisible = props.hint and props.forceHintVisible -- Generate tags based on state local tags = "Slot" From 725ccf1050716d7bb40a4f3dc1a1f8e19e21c34e Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 9 Apr 2026 19:34:07 -0700 Subject: [PATCH 174/186] Bump version Signed-off-by: Ryan Luu --- wally.lock | 2 +- wally.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wally.lock b/wally.lock index 7a45f262..55738e11 100644 --- a/wally.lock +++ b/wally.lock @@ -89,7 +89,7 @@ dependencies = [["collections", "jsdotlua/collections@1.2.7"]] [[package]] name = "ryanlua/satchel" -version = "1.4.1" +version = "2.0.0" dependencies = [["react", "jsdotlua/react@17.2.1"], ["react-roblox", "jsdotlua/react-roblox@17.2.1"], ["topbarplus", "ryanlua/topbarplus@1.0.1"]] [[package]] diff --git a/wally.toml b/wally.toml index 1c78e51f..0df25c94 100644 --- a/wally.toml +++ b/wally.toml @@ -1,7 +1,7 @@ [package] name = "ryanlua/satchel" description = "A modern open-source alternative to Roblox's default backpack." -version = "1.4.1" +version = "2.0.0" license = "MPL-2.0" authors = ["Ryan Luu "] realm = "shared" From 5335a7518fe89474a4f73760893acd81965afd33 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 9 Apr 2026 19:47:03 -0700 Subject: [PATCH 175/186] Fix number hints showing in inventory Signed-off-by: Ryan Luu --- src/Components/Slot.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Slot.luau b/src/Components/Slot.luau index ea19b996..f7e76544 100644 --- a/src/Components/Slot.luau +++ b/src/Components/Slot.luau @@ -30,7 +30,7 @@ local function Slot(props: Props) slotNumber = "0" end - local hintVisible = props.hint and props.forceHintVisible + local hintVisible = props.hint == true and props.forceHintVisible -- Generate tags based on state local tags = "Slot" From 6f3e5a9cddfee297258c9dd7ec4032cd6f5fe0ae Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 10 Apr 2026 15:04:52 -0700 Subject: [PATCH 176/186] Use require by string Signed-off-by: Ryan Luu --- src/Api/getTopbarIcon.luau | 2 +- src/Api/setEnabled.luau | 2 +- src/Client.client.luau | 8 ++++---- src/Components/App.luau | 8 ++++---- src/Components/App.story.luau | 4 ++-- src/Components/Backpack.luau | 6 +++--- src/Components/Backpack.story.luau | 4 ++-- src/Components/Hotbar.luau | 4 ++-- src/Components/Hotbar.story.luau | 4 ++-- src/Components/HotbarHint.luau | 2 +- src/Components/HotbarHint.story.luau | 4 ++-- src/Components/Inventory.luau | 6 +++--- src/Components/Inventory.story.luau | 4 ++-- src/Components/InventoryHint.luau | 2 +- src/Components/InventoryHint.story.luau | 4 ++-- src/Components/Satchel.storybook.luau | 4 ++-- src/Components/Searchbar.luau | 2 +- src/Components/Searchbar.story.luau | 4 ++-- src/Components/Slot.luau | 4 ++-- src/Components/Slot.story.luau | 4 ++-- src/Components/Tooltip.luau | 2 +- src/Components/Tooltip.story.luau | 4 ++-- src/CoreGuiWarn.client.luau | 3 ++- src/TopbarIcon.client.luau | 4 ++-- tests/SatchelEnabled.client.luau | 4 ++-- tests/SwitchTheme.client.luau | 4 ++-- 26 files changed, 52 insertions(+), 51 deletions(-) diff --git a/src/Api/getTopbarIcon.luau b/src/Api/getTopbarIcon.luau index 1260b8f4..d122ccef 100644 --- a/src/Api/getTopbarIcon.luau +++ b/src/Api/getTopbarIcon.luau @@ -2,7 +2,7 @@ local RunService = game:GetService("RunService") -local TopbarPlus = require(script.Parent.Parent.Parent.topbarplus) +local TopbarPlus = require("../../topbarplus") local function getTopbarIcon(): TopbarPlus.Icon? assert(RunService:IsClient(), "getTopbarIcon can only be called on the client") diff --git a/src/Api/setEnabled.luau b/src/Api/setEnabled.luau index 5b93604a..e0acc339 100644 --- a/src/Api/setEnabled.luau +++ b/src/Api/setEnabled.luau @@ -3,7 +3,7 @@ local Players = game:GetService("Players") local RunService = game:GetService("RunService") -local getTopbarIcon = require(script.Parent.getTopbarIcon) +local getTopbarIcon = require("./getTopbarIcon") local player = Players.LocalPlayer local playerGui = player:WaitForChild("PlayerGui") diff --git a/src/Client.client.luau b/src/Client.client.luau index 6adcf03d..af1bb7bf 100644 --- a/src/Client.client.luau +++ b/src/Client.client.luau @@ -9,11 +9,11 @@ local UserInputService = game:GetService("UserInputService") -- selene: allow(global_usage) _G.__DEV__ = RunService:IsStudio() -local React = require(script.Parent.Parent.react) -local ReactRoblox = require(script.Parent.Parent["react-roblox"]) -local closeInventory = require(script.Parent.Api.closeInventory) +local React = require("../react") +local ReactRoblox = require("../react-roblox") +local closeInventory = require("./Api/closeInventory") -local App = require(script.Parent.Components.App) +local App = require("./Components/App") local DESIGN_SHEET = script.Parent.Design.SatchelStyleSheet diff --git a/src/Components/App.luau b/src/Components/App.luau index 508da540..e8983dd4 100644 --- a/src/Components/App.luau +++ b/src/Components/App.luau @@ -1,10 +1,10 @@ --!strict -local React = require(script.Parent.Parent.Parent.react) +local React = require("../../react") -local Backpack = require(script.Parent.Backpack) -local HotbarHint = require(script.Parent.HotbarHint) -local InventoryHint = require(script.Parent.InventoryHint) +local Backpack = require("./Backpack") +local HotbarHint = require("./HotbarHint") +local InventoryHint = require("./InventoryHint") local InventoryBindings = script.Parent.Parent.Bindings.InventoryContext local RemoveFromHotbarGamepadKeyCode = InventoryBindings.RemoveFromHotbarAction.GamepadBinding.KeyCode diff --git a/src/Components/App.story.luau b/src/Components/App.story.luau index 6ca53a31..3f2cd22c 100644 --- a/src/Components/App.story.luau +++ b/src/Components/App.story.luau @@ -1,8 +1,8 @@ --!strict -local React = require(script.Parent.Parent.Parent.react) +local React = require("../../react") -local App = require(script.Parent.App) +local App = require("./App") local controls = { hintVisible = true, diff --git a/src/Components/Backpack.luau b/src/Components/Backpack.luau index 988c9f11..de54a11f 100644 --- a/src/Components/Backpack.luau +++ b/src/Components/Backpack.luau @@ -1,9 +1,9 @@ --!strict -local React = require(script.Parent.Parent.Parent.react) +local React = require("../../react") -local Hotbar = require(script.Parent.Hotbar) -local Inventory = require(script.Parent.Inventory) +local Hotbar = require("./Hotbar") +local Inventory = require("./Inventory") export type Props = { forceKeyboardHintVisible: boolean?, diff --git a/src/Components/Backpack.story.luau b/src/Components/Backpack.story.luau index c9bcd462..d4fbced4 100644 --- a/src/Components/Backpack.story.luau +++ b/src/Components/Backpack.story.luau @@ -1,8 +1,8 @@ --!strict -local React = require(script.Parent.Parent.Parent.react) +local React = require("../../react") -local Backpack = require(script.Parent.Backpack) +local Backpack = require("./Backpack") local controls = { slots = 10, diff --git a/src/Components/Hotbar.luau b/src/Components/Hotbar.luau index a3dbf6f9..30f20352 100644 --- a/src/Components/Hotbar.luau +++ b/src/Components/Hotbar.luau @@ -1,8 +1,8 @@ --!strict -local React = require(script.Parent.Parent.Parent.react) +local React = require("../../react") -local Slot = require(script.Parent.Slot) +local Slot = require("./Slot") export type Props = { forceKeyboardHintVisible: boolean?, diff --git a/src/Components/Hotbar.story.luau b/src/Components/Hotbar.story.luau index 6b9645db..0e01bda9 100644 --- a/src/Components/Hotbar.story.luau +++ b/src/Components/Hotbar.story.luau @@ -1,8 +1,8 @@ --!strict -local React = require(script.Parent.Parent.Parent.react) +local React = require("../../react") -local Hotbar = require(script.Parent.Hotbar) +local Hotbar = require("./Hotbar") local controls = { slots = 10, diff --git a/src/Components/HotbarHint.luau b/src/Components/HotbarHint.luau index 24308229..3f9a3bba 100644 --- a/src/Components/HotbarHint.luau +++ b/src/Components/HotbarHint.luau @@ -2,7 +2,7 @@ local UserInputService = game:GetService("UserInputService") -local React = require(script.Parent.Parent.Parent.react) +local React = require("../../react") export type Props = { keyCode: Enum.KeyCode, diff --git a/src/Components/HotbarHint.story.luau b/src/Components/HotbarHint.story.luau index aae63226..16654a56 100644 --- a/src/Components/HotbarHint.story.luau +++ b/src/Components/HotbarHint.story.luau @@ -1,8 +1,8 @@ --!strict -local React = require(script.Parent.Parent.Parent.react) +local React = require("../../react") -local HotbarHint = require(script.Parent.HotbarHint) +local HotbarHint = require("./HotbarHint") return { name = "Hotbar Hint", diff --git a/src/Components/Inventory.luau b/src/Components/Inventory.luau index 356de0c5..899236d8 100644 --- a/src/Components/Inventory.luau +++ b/src/Components/Inventory.luau @@ -1,9 +1,9 @@ --!strict -local React = require(script.Parent.Parent.Parent.react) +local React = require("../../react") -local Searchbar = require(script.Parent.Searchbar) -local Slot = require(script.Parent.Slot) +local Searchbar = require("./Searchbar") +local Slot = require("./Slot") export type Props = { width: number?, diff --git a/src/Components/Inventory.story.luau b/src/Components/Inventory.story.luau index ba53c6d5..ff1dd7cf 100644 --- a/src/Components/Inventory.story.luau +++ b/src/Components/Inventory.story.luau @@ -1,8 +1,8 @@ --!strict -local React = require(script.Parent.Parent.Parent.react) +local React = require("../../react") -local Inventory = require(script.Parent.Inventory) +local Inventory = require("./Inventory") local controls = { toolName = "Sword", diff --git a/src/Components/InventoryHint.luau b/src/Components/InventoryHint.luau index cc10c762..da13ec3f 100644 --- a/src/Components/InventoryHint.luau +++ b/src/Components/InventoryHint.luau @@ -2,7 +2,7 @@ local UserInputService = game:GetService("UserInputService") -local React = require(script.Parent.Parent.Parent.react) +local React = require("../../react") export type Props = { keyCode: Enum.KeyCode, diff --git a/src/Components/InventoryHint.story.luau b/src/Components/InventoryHint.story.luau index c4e6c5b7..3a8f58bc 100644 --- a/src/Components/InventoryHint.story.luau +++ b/src/Components/InventoryHint.story.luau @@ -1,8 +1,8 @@ --!strict -local React = require(script.Parent.Parent.Parent.react) +local React = require("../../react") -local InventoryHint = require(script.Parent.InventoryHint) +local InventoryHint = require("./InventoryHint") local controls = { text = "Remove from Hotbar", diff --git a/src/Components/Satchel.storybook.luau b/src/Components/Satchel.storybook.luau index bb405c95..ee5c2dd1 100644 --- a/src/Components/Satchel.storybook.luau +++ b/src/Components/Satchel.storybook.luau @@ -1,7 +1,7 @@ --!strict -local React = require(script.Parent.Parent.Parent.react) -local ReactRoblox = require(script.Parent.Parent.Parent["react-roblox"]) +local React = require("../../react") +local ReactRoblox = require("../../react-roblox") local DESIGN_SHEET = script.Parent.Parent.Design.SatchelStyleSheet diff --git a/src/Components/Searchbar.luau b/src/Components/Searchbar.luau index 70a10f97..ed62b3fc 100644 --- a/src/Components/Searchbar.luau +++ b/src/Components/Searchbar.luau @@ -1,6 +1,6 @@ --!strict -local React = require(script.Parent.Parent.Parent.react) +local React = require("../../react") export type Props = { size: UDim2?, diff --git a/src/Components/Searchbar.story.luau b/src/Components/Searchbar.story.luau index f2ba6f87..73c90013 100644 --- a/src/Components/Searchbar.story.luau +++ b/src/Components/Searchbar.story.luau @@ -1,8 +1,8 @@ --!strict -local React = require(script.Parent.Parent.Parent.react) +local React = require("../../react") -local Searchbar = require(script.Parent.Searchbar) +local Searchbar = require("./Searchbar") return { summary = "Search for items in the inventory", diff --git a/src/Components/Slot.luau b/src/Components/Slot.luau index f7e76544..3f68ef9b 100644 --- a/src/Components/Slot.luau +++ b/src/Components/Slot.luau @@ -1,8 +1,8 @@ --!strict -local React = require(script.Parent.Parent.Parent.react) +local React = require("../../react") -local Tooltip = require(script.Parent.Tooltip) +local Tooltip = require("./Tooltip") export type Props = { item: (Tool | HopperBin)?, diff --git a/src/Components/Slot.story.luau b/src/Components/Slot.story.luau index 078e314d..c4e1c4e8 100644 --- a/src/Components/Slot.story.luau +++ b/src/Components/Slot.story.luau @@ -1,8 +1,8 @@ --!strict -local React = require(script.Parent.Parent.Parent.react) +local React = require("../../react") -local Slot = require(script.Parent.Slot) +local Slot = require("./Slot") local controls = { toolName = "Sword", diff --git a/src/Components/Tooltip.luau b/src/Components/Tooltip.luau index c6a2cec1..68d2ecc2 100644 --- a/src/Components/Tooltip.luau +++ b/src/Components/Tooltip.luau @@ -1,6 +1,6 @@ --!strict -local React = require(script.Parent.Parent.Parent.react) +local React = require("../../react") export type Props = { text: string?, diff --git a/src/Components/Tooltip.story.luau b/src/Components/Tooltip.story.luau index 60d857d3..8d6bc0af 100644 --- a/src/Components/Tooltip.story.luau +++ b/src/Components/Tooltip.story.luau @@ -1,8 +1,8 @@ --!strict -local React = require(script.Parent.Parent.Parent.react) +local React = require("../../react") -local Tooltip = require(script.Parent.Tooltip) +local Tooltip = require("./Tooltip") local controls = { text = "I'm a tooltip!", diff --git a/src/CoreGuiWarn.client.luau b/src/CoreGuiWarn.client.luau index 29b8e3cd..88f12e56 100644 --- a/src/CoreGuiWarn.client.luau +++ b/src/CoreGuiWarn.client.luau @@ -1,7 +1,8 @@ --!strict local StarterGui = game:GetService("StarterGui") -local Satchel = require(script.Parent) + +local Satchel = require("./") task.spawn(function() while task.wait(1) do diff --git a/src/TopbarIcon.client.luau b/src/TopbarIcon.client.luau index b08a9fe8..ec5f8ae4 100644 --- a/src/TopbarIcon.client.luau +++ b/src/TopbarIcon.client.luau @@ -1,7 +1,7 @@ --!strict -local Icon = require(script.Parent.Parent.topbarplus) -local Satchel = require(script.Parent) +local Icon = require("../topbarplus") +local Satchel = require("./") local icon = Icon.new() icon:setName("SatchelInventory") diff --git a/tests/SatchelEnabled.client.luau b/tests/SatchelEnabled.client.luau index 66ed946e..eaa36f35 100644 --- a/tests/SatchelEnabled.client.luau +++ b/tests/SatchelEnabled.client.luau @@ -2,8 +2,8 @@ local StarterGui = game:GetService("StarterGui") -local Icon = require(script.Parent.Satchel.Packages.topbarplus) -local Satchel = require(script.Parent.Satchel) +local Icon = require("./Satchel/Packages/topbarplus") +local Satchel = require("./Satchel") local icon = Icon.new() icon:modifyTheme({ diff --git a/tests/SwitchTheme.client.luau b/tests/SwitchTheme.client.luau index 1d3e8ca0..9e96d806 100644 --- a/tests/SwitchTheme.client.luau +++ b/tests/SwitchTheme.client.luau @@ -1,7 +1,7 @@ --!strict -local Icon = require(script.Parent.Satchel.Packages.topbarplus) -local Satchel = require(script.Parent.Satchel) +local Icon = require("./Satchel/Packages/topbarplus") +local Satchel = require("./Satchel") local icon = Icon.new() icon:modifyTheme({ From ca762a5ba8a3476d8d25565f1f87317e1b9c731c Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 10 Apr 2026 15:25:13 -0700 Subject: [PATCH 177/186] Use styling for forcing visibility Signed-off-by: Ryan Luu --- src/Components/HotbarHint.luau | 9 +- src/Components/InventoryHint.luau | 8 +- src/Design.rbxmx | 768 +++++++++++++++--------------- 3 files changed, 403 insertions(+), 382 deletions(-) diff --git a/src/Components/HotbarHint.luau b/src/Components/HotbarHint.luau index 3f9a3bba..7ef580bc 100644 --- a/src/Components/HotbarHint.luau +++ b/src/Components/HotbarHint.luau @@ -12,12 +12,15 @@ export type Props = { } local function HotbarHint(props: Props) - local visible = props.visible and props.forceVisible + local tags = "HotbarHint" + if props.forceVisible then + tags = tags .. " Visible" + end return React.createElement("Frame", { LayoutOrder = props.order, - Visible = visible, - [React.Tag] = "HotbarHint", + Visible = props.visible, + [React.Tag] = tags, }, { KeyCode = React.createElement("ImageLabel", { Image = UserInputService:GetImageForKeyCode(props.keyCode), diff --git a/src/Components/InventoryHint.luau b/src/Components/InventoryHint.luau index da13ec3f..711c1c10 100644 --- a/src/Components/InventoryHint.luau +++ b/src/Components/InventoryHint.luau @@ -12,10 +12,14 @@ export type Props = { } local function InventoryHint(props: Props) + local tags = "InventoryHint" + if props.forceVisible then + tags = tags .. " Visible" + end + return React.createElement("Frame", { LayoutOrder = props.order, - Visible = props.forceVisible, - [React.Tag] = "InventoryHint", + [React.Tag] = tags, }, { KeyCode = React.createElement("ImageLabel", { Image = UserInputService:GetImageForKeyCode(props.keyCode), diff --git a/src/Design.rbxmx b/src/Design.rbxmx index e3fa022b..8660507d 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,23 +11,7 @@ -1 - - - - 0 - false - ThemeTokens - -1 - - - - + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= 0 @@ -36,10 +20,10 @@ Pw==]]> -1 - + 0 - RBXB86CE5B111EA4B6CB3012A38E1F0D818 + RBX597525B19488436AA33F0688DED3EFBF 0 false @@ -49,7 +33,7 @@ Pw==]]> - + -1 - + 0 - RBXB86CE5B111EA4B6CB3012A38E1F0D818 + RBX597525B19488436AA33F0688DED3EFBF 0 false @@ -84,7 +68,7 @@ bmRDb2xvcg/NzMw+zczMPs3MzD4OAAAAVG9vbFRpcFBhZGRpbmcJAAAAAAIAAAA=]]> - + 0 @@ -93,7 +77,7 @@ bmRDb2xvcg/NzMw+zczMPs3MzD4OAAAAVG9vbFRpcFBhZGRpbmcJAAAAAAIAAAA=]]>-1 - + 0 -1 - + 0 -1 - + 0 AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== @@ -137,85 +121,7 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAA==]]> - - - 0 - AQAAAAcAAABWaXNpYmxlAwE= - - @PreferredInputGamepad - - 0 - false - @PreferredInputGamepad - -1 - - - - - - - 0 - - - .InventoryHint - - 0 - false - .InventoryHint - -1 - - - - - 0 - - - >ImageLabel - - 0 - false - >ImageLabel - -1 - - - - - 0 - AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - - - - 0 - - - >TextLabel - - 0 - false - >TextLabel - -1 - - - - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -230,39 +136,27 @@ VGV4dFNpemU=]]> - - - 0 - RBX888462ECA72C4ACB8B0AF5B10CCFAADF - - 0 - false - Derive from DefaultTheme - -1 - - - - + 0 - + - .HotbarHints + .Hints 0 false - .HotbarHints + .Hints -1 - + 0 - + ::UIListLayout @@ -274,7 +168,7 @@ QWxpZ25tZW50AgAAAA==]]> - + 0 -1 - + 0 - + AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= - ::UIPadding + ::UICorner 0 false - ::UIPadding + ::UICorner -1 - + 0 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= + - ::UICorner + ::UIPadding 0 false - ::UICorner + ::UIPadding -1 - + 0 -1 - + 0 AAAAAA== @@ -373,7 +267,7 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAA==]]> - + 0 -1 - - - 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - - - 0 - - - ::UIPadding - - 0 - false - ::UIPadding - -1 - - - - - - 0 - AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA - - ::UIListLayout - - 0 - false - ::UIListLayout - -1 - - - - + 0 -1 - + 0 - - - - 0 - - - TextLabel.Tooltip - - 0 - false - TextLabel.Tooltip - -1 - - - + 0 - + AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA - ::UIPadding + ::UIListLayout 0 false - ::UIPadding + ::UIListLayout -1 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz ::UICorner @@ -518,67 +346,88 @@ ZGluZwoAAABQYWRkaW5nVG9wAg8AAAAkVG9vbFRpcFBhZGRpbmc=]]> + + + 0 + + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + - + 0 - + - .Hotbar + TextLabel.Tooltip 0 false - .Hotbar + TextLabel.Tooltip -1 - + 0 - AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz - ::UIPadding + ::UICorner 0 false - ::UIPadding + ::UICorner -1 - + 0 - + - ::UIListLayout + ::UIPadding 0 false - ::UIListLayout + ::UIPadding -1 - + 0 - + - .InventoryHints + .Backpack 0 false - .InventoryHints + .Backpack -1 - + 0 AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= @@ -593,24 +442,39 @@ dW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/]]> - + 0 - - - .Backpack + RBX37676FEA32EC44EE85F071FAA3D8B38E 0 false - .Backpack + Derive from DefaultTheme + -1 + + + + + + 0 + + + .HotbarHints + + 0 + false + .HotbarHints -1 - + 0 - AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= + ::UIListLayout @@ -622,7 +486,7 @@ ABYAAABCYWNrZ3JvdW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/]]> - + 0 -1 - + 0 - + - ::UITextSizeConstraint + >ImageLabel 0 false - ::UITextSizeConstraint + >ImageLabel -1 + + + 0 + AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== + + ::UICorner + + 0 + false + ::UICorner + -1 + + + - + + + 0 + AAAAAA== + + .Equipped + + 0 + false + .Equipped + -1 + + + + + 0 + + + ::UIStroke + + 0 + false + ::UIStroke + -1 + + + + + 0 - + 0 AAAAAA== - .Equipped + :Press 0 false - .Equipped + :Press -1 - + 0 - + AQAAAAcAAABWaXNpYmxlAwE= - ::UIStroke + >.Tooltip 0 false - ::UIStroke + >.Tooltip -1 - + 0 - + AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz - .Unlocked + ::UICorner 0 false - .Unlocked + ::UICorner + -1 + + + + + + 0 + AgAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAAHAAAAVmlzaWJsZQMA + + >TextLabel + + 0 + false + >TextLabel -1 - + 0 - AAAAAA== + - :Press + .SlotNumber 0 false - :Press + .SlotNumber -1 - + 0 - + AQAAAAcAAABWaXNpYmxlAwE= - ::UIStroke + @PreferredInputKeyboardAndMouse 0 false - ::UIStroke + @PreferredInputKeyboardAndMouse -1 + + + 0 + AQAAAAcAAABWaXNpYmxlAwA= + + .Tooltip + + 0 + false + .Tooltip + -1 + + + - + 0 AAAAAA== @@ -761,7 +698,7 @@ cgIVAAAAJFNsb3RQcmVzc1N0cm9rZUNvbG9yCQAAAFRoaWNrbmVzcwYAAAAAAAAAQA==]]>-1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -776,81 +713,178 @@ cgIVAAAAJFNsb3RQcmVzc1N0cm9rZUNvbG9yCQAAAFRoaWNrbmVzcwYAAAAAAAAAQA==]]> - + 0 - AAAAAA== + - :Press + ::UITextSizeConstraint 0 false - :Press + ::UITextSizeConstraint -1 - + + + + 0 + + + .Unlocked + + 0 + false + .Unlocked + -1 + + + 0 - AQAAAAcAAABWaXNpYmxlAwE= + AAAAAA== - >.Tooltip + :Press 0 false - >.Tooltip + :Press -1 + + + 0 + + + ::UIStroke + + 0 + false + ::UIStroke + -1 + + + - + + + + 0 + + + .InventoryHints + + 0 + false + .InventoryHints + -1 + + + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz + AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= - ::UICorner + ::UIListLayout 0 false - ::UICorner + ::UIListLayout -1 - + + + + 0 + + + .Hotbar + + 0 + false + .Hotbar + -1 + + + 0 - + - >ImageLabel + ::UIListLayout 0 false - >ImageLabel + ::UIListLayout -1 - - - 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - + 0 - AgAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAAHAAAAVmlzaWJsZQMA + AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + + + + + 0 + + + .InventoryHint + + 0 + false + .InventoryHint + -1 + + + + + 0 + AQAAAAcAAABWaXNpYmxlAwE= + + @PreferredInputGamepad + + 0 + false + @PreferredInputGamepad + -1 + + + + + + 0 + >TextLabel @@ -860,90 +894,54 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> -1 - - - 0 - AQAAAAcAAABWaXNpYmxlAwA= - - .Tooltip - - 0 - false - .Tooltip - -1 - - - - + + + + 0 + + + >ImageLabel + + 0 + false + >ImageLabel + -1 + + + 0 - + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== - .SlotNumber + ::UIAspectRatioConstraint 0 false - .SlotNumber + ::UIAspectRatioConstraint -1 - - - 0 - AQAAAAcAAABWaXNpYmxlAwE= - - @PreferredInputKeyboardAndMouse - - 0 - false - @PreferredInputKeyboardAndMouse - -1 - - - - + - 0 - + 9 + AQAAAAcAAABWaXNpYmxlAwE= - .Hints + .Visible 0 false - .Hints + .Visible -1 - - - 0 - - - ::UIListLayout - - 0 - false - ::UIListLayout - -1 - - - - + -1 - + 0 - RBX58C39F64B8D947F1B579177318A372BB + RBXB2E2303B06E24171A3A616F9D757C70D 0 false @@ -997,5 +995,21 @@ VGV4dFNpemU=]]> + + + + 0 + false + ThemeTokens + -1 + + + \ No newline at end of file From e9f86aa13643bf97afe1a08870a709048614e21f Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 11 Apr 2026 19:14:36 -0700 Subject: [PATCH 178/186] Switch local usage to const Signed-off-by: Ryan Luu --- src/Api/closeInventory.luau | 6 +-- src/Api/getEnabled.luau | 12 ++--- src/Api/getTheme.luau | 8 ++-- src/Api/getTopbarIcon.luau | 6 +-- src/Api/isInventoryOpen.luau | 6 +-- src/Api/openInventory.luau | 6 +-- src/Api/setEnabled.luau | 16 +++---- src/Api/setTheme.luau | 12 ++--- src/Attribution.client.luau | 8 ++-- src/Client.client.luau | 58 ++++++++++++------------- src/Components/App.luau | 28 ++++++------ src/Components/App.story.luau | 8 ++-- src/Components/Backpack.luau | 16 +++---- src/Components/Backpack.story.luau | 8 ++-- src/Components/Hotbar.luau | 14 +++--- src/Components/Hotbar.story.luau | 8 ++-- src/Components/HotbarHint.luau | 6 +-- src/Components/HotbarHint.story.luau | 4 +- src/Components/Inventory.luau | 16 +++---- src/Components/Inventory.story.luau | 8 ++-- src/Components/InventoryHint.luau | 6 +-- src/Components/InventoryHint.story.luau | 6 +-- src/Components/Satchel.storybook.luau | 6 +-- src/Components/Searchbar.luau | 6 +-- src/Components/Searchbar.story.luau | 4 +- src/Components/Slot.luau | 18 ++++---- src/Components/Slot.story.luau | 8 ++-- src/Components/Tooltip.luau | 4 +- src/Components/Tooltip.story.luau | 6 +-- src/CoreGuiWarn.client.luau | 4 +- src/TopbarIcon.client.luau | 6 +-- src/init.luau | 2 +- tests/SatchelEnabled.client.luau | 8 ++-- tests/SwitchTheme.client.luau | 6 +-- 34 files changed, 172 insertions(+), 172 deletions(-) diff --git a/src/Api/closeInventory.luau b/src/Api/closeInventory.luau index f53e0841..40f5af60 100644 --- a/src/Api/closeInventory.luau +++ b/src/Api/closeInventory.luau @@ -1,10 +1,10 @@ --!strict -local RunService = game:GetService("RunService") +const RunService = game:GetService("RunService") -local bindableEvents = script.Parent.Parent.BindableEvents +const bindableEvents = script.Parent.Parent.BindableEvents -local function closeInventory(): () +const function closeInventory(): () assert(RunService:IsClient(), "closeInventory can only be called on the client") bindableEvents.InventoryClosed:Fire() diff --git a/src/Api/getEnabled.luau b/src/Api/getEnabled.luau index 18efbb59..8a6b3d35 100644 --- a/src/Api/getEnabled.luau +++ b/src/Api/getEnabled.luau @@ -1,13 +1,13 @@ --!strict -local Players = game:GetService("Players") -local RunService = game:GetService("RunService") +const Players = game:GetService("Players") +const RunService = game:GetService("RunService") -local player = Players.LocalPlayer -local playerGui = player:WaitForChild("PlayerGui") -local screenGui = playerGui:WaitForChild("SatchelGui") +const player = Players.LocalPlayer +const playerGui = player:WaitForChild("PlayerGui") +const screenGui = playerGui:WaitForChild("SatchelGui") -local function getEnabled(): boolean +const function getEnabled(): boolean assert(RunService:IsClient(), "getEnabled can only be called on the client") return screenGui.Enabled diff --git a/src/Api/getTheme.luau b/src/Api/getTheme.luau index 60b55796..899a2714 100644 --- a/src/Api/getTheme.luau +++ b/src/Api/getTheme.luau @@ -1,13 +1,13 @@ --!strict -local RunService = game:GetService("RunService") +const RunService = game:GetService("RunService") -local currentStyleSheet = script.Parent.Parent.Design.SatchelStyleSheet +const currentStyleSheet = script.Parent.Parent.Design.SatchelStyleSheet -local function getTheme(): StyleSheet +const function getTheme(): StyleSheet assert(RunService:IsClient(), "getTheme can only be called on the client") - local currentTheme = currentStyleSheet:FindFirstChildWhichIsA("StyleDerive").StyleSheet + const currentTheme = currentStyleSheet:FindFirstChildWhichIsA("StyleDerive").StyleSheet return currentTheme end diff --git a/src/Api/getTopbarIcon.luau b/src/Api/getTopbarIcon.luau index d122ccef..d6ef2784 100644 --- a/src/Api/getTopbarIcon.luau +++ b/src/Api/getTopbarIcon.luau @@ -1,10 +1,10 @@ --!strict -local RunService = game:GetService("RunService") +const RunService = game:GetService("RunService") -local TopbarPlus = require("../../topbarplus") +const TopbarPlus = require("../../topbarplus") -local function getTopbarIcon(): TopbarPlus.Icon? +const function getTopbarIcon(): TopbarPlus.Icon? assert(RunService:IsClient(), "getTopbarIcon can only be called on the client") return TopbarPlus.getIcon("SatchelInventory") diff --git a/src/Api/isInventoryOpen.luau b/src/Api/isInventoryOpen.luau index 42e8eb2b..43bff2ce 100644 --- a/src/Api/isInventoryOpen.luau +++ b/src/Api/isInventoryOpen.luau @@ -1,8 +1,8 @@ --!strict -local RunService = game:GetService("RunService") +const RunService = game:GetService("RunService") -local bindableEvents = script.Parent.Parent.BindableEvents +const bindableEvents = script.Parent.Parent.BindableEvents local inventoryOpen = false @@ -14,7 +14,7 @@ bindableEvents.InventoryClosed.Event:Connect(function() inventoryOpen = false end) -local function isInventoryOpen(): boolean +const function isInventoryOpen(): boolean assert(RunService:IsClient(), "isInventoryOpen can only be called on the client") return inventoryOpen diff --git a/src/Api/openInventory.luau b/src/Api/openInventory.luau index a3f6a73b..32ebc0a1 100644 --- a/src/Api/openInventory.luau +++ b/src/Api/openInventory.luau @@ -1,10 +1,10 @@ --!strict -local RunService = game:GetService("RunService") +const RunService = game:GetService("RunService") -local bindableEvents = script.Parent.Parent.BindableEvents +const bindableEvents = script.Parent.Parent.BindableEvents -local function openInventory(): () +const function openInventory(): () assert(RunService:IsClient(), "openInventory can only be called on the client") bindableEvents.InventoryOpened:Fire() diff --git a/src/Api/setEnabled.luau b/src/Api/setEnabled.luau index e0acc339..6090abf6 100644 --- a/src/Api/setEnabled.luau +++ b/src/Api/setEnabled.luau @@ -1,20 +1,20 @@ --!strict -local Players = game:GetService("Players") -local RunService = game:GetService("RunService") +const Players = game:GetService("Players") +const RunService = game:GetService("RunService") -local getTopbarIcon = require("./getTopbarIcon") +const getTopbarIcon = require("./getTopbarIcon") -local player = Players.LocalPlayer -local playerGui = player:WaitForChild("PlayerGui") -local screenGui = playerGui:WaitForChild("SatchelGui") +const player = Players.LocalPlayer +const playerGui = player:WaitForChild("PlayerGui") +const screenGui = playerGui:WaitForChild("SatchelGui") -local function setEnabled(enabled: boolean): () +const function setEnabled(enabled: boolean): () assert(RunService:IsClient(), "setEnabled can only be called on the client") screenGui.Enabled = enabled - local icon = getTopbarIcon() + const icon = getTopbarIcon() if icon then icon:setEnabled(enabled) end diff --git a/src/Api/setTheme.luau b/src/Api/setTheme.luau index 46333de3..afc17c42 100644 --- a/src/Api/setTheme.luau +++ b/src/Api/setTheme.luau @@ -1,16 +1,16 @@ --!strict -local RunService = game:GetService("RunService") +const RunService = game:GetService("RunService") -local bindableEvents = script.Parent.Parent.BindableEvents -local styleSheets = script.Parent.Parent.Design -local currentTheme = styleSheets.SatchelStyleSheet:FindFirstChildWhichIsA("StyleDerive") +const bindableEvents = script.Parent.Parent.BindableEvents +const styleSheets = script.Parent.Parent.Design +const currentTheme = styleSheets.SatchelStyleSheet:FindFirstChildWhichIsA("StyleDerive") -- TODO: Add autocomplete for default themes -local function setTheme(theme: string | StyleSheet) +const function setTheme(theme: string | StyleSheet) assert(RunService:IsClient(), "setTheme can only be called on the client") - local newTheme = if typeof(theme) == "string" then styleSheets:WaitForChild(theme) else theme + const newTheme = if typeof(theme) == "string" then styleSheets:WaitForChild(theme) else theme currentTheme.StyleSheet = newTheme bindableEvents.ThemeChanged:Fire(newTheme) diff --git a/src/Attribution.client.luau b/src/Attribution.client.luau index 41ee5989..e3c4d395 100644 --- a/src/Attribution.client.luau +++ b/src/Attribution.client.luau @@ -18,10 +18,10 @@ Thank you for supporting Satchel. ]] -local MarketplaceService = game:GetService("MarketplaceService") -local RunService = game:GetService("RunService") +const MarketplaceService = game:GetService("MarketplaceService") +const RunService = game:GetService("RunService") -local VERSION = "2.0.0" +const VERSION = "2.0.0" -- Print attribution. Do not modify without reading above if not RunService:IsStudio() and RunService:IsClient() then @@ -31,7 +31,7 @@ end -- Check for updates. You may modify the below local latestVersion: string? -local success, result = pcall(function() +const success, result = pcall(function() return MarketplaceService:GetProductInfoAsync(13947506401) end) diff --git a/src/Client.client.luau b/src/Client.client.luau index af1bb7bf..8d28b111 100644 --- a/src/Client.client.luau +++ b/src/Client.client.luau @@ -1,48 +1,48 @@ --!strict -local GuiService = game:GetService("GuiService") -local Players = game:GetService("Players") -local RunService = game:GetService("RunService") -local StarterGui = game:GetService("StarterGui") -local UserInputService = game:GetService("UserInputService") +const GuiService = game:GetService("GuiService") +const Players = game:GetService("Players") +const RunService = game:GetService("RunService") +const StarterGui = game:GetService("StarterGui") +const UserInputService = game:GetService("UserInputService") -- selene: allow(global_usage) _G.__DEV__ = RunService:IsStudio() -local React = require("../react") -local ReactRoblox = require("../react-roblox") -local closeInventory = require("./Api/closeInventory") +const React = require("../react") +const ReactRoblox = require("../react-roblox") +const closeInventory = require("./Api/closeInventory") -local App = require("./Components/App") +const App = require("./Components/App") -local DESIGN_SHEET = script.Parent.Design.SatchelStyleSheet +const DESIGN_SHEET = script.Parent.Design.SatchelStyleSheet -local player = Players.LocalPlayer -local playerGui = player:WaitForChild("PlayerGui") +const player = Players.LocalPlayer +const playerGui = player:WaitForChild("PlayerGui") StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false) -local handle = Instance.new("ScreenGui") +const handle = Instance.new("ScreenGui") handle.Name = "SatchelGui" handle.ResetOnSpawn = false handle.Parent = playerGui -local root = ReactRoblox.createRoot(handle) +const root = ReactRoblox.createRoot(handle) -local function Satchel() +const function Satchel() -- Open and close backpack based on bindable events - local opened, setOpened = React.useState(false) + const opened, setOpened = React.useState(false) React.useEffect(function() - local bindableEvents = script.Parent.BindableEvents + const bindableEvents = script.Parent.BindableEvents - local inventoryOpenedSignal = bindableEvents.InventoryOpened.Event:Connect(function() + const inventoryOpenedSignal = bindableEvents.InventoryOpened.Event:Connect(function() setOpened(true) end) - local inventoryClosedSignal = bindableEvents.InventoryClosed.Event:Connect(function() + const inventoryClosedSignal = bindableEvents.InventoryClosed.Event:Connect(function() setOpened(false) end) - local menuOpenedSignal = GuiService.MenuOpened:Connect(function() + const menuOpenedSignal = GuiService.MenuOpened:Connect(function() closeInventory() end) @@ -55,8 +55,8 @@ local function Satchel() -- Close backpack when clicking outside of it React.useEffect(function() - local inputSignal = UserInputService.InputBegan:Connect(function(input, gameProcessedEvent) - local inputType = input.UserInputType + const inputSignal = UserInputService.InputBegan:Connect(function(input, gameProcessedEvent) + const inputType = input.UserInputType if not gameProcessedEvent then if inputType == Enum.UserInputType.MouseButton1 or inputType == Enum.UserInputType.Touch then closeInventory() @@ -70,13 +70,13 @@ local function Satchel() end, {}) -- Change slots based on viewport display size - local slots, setSlots = React.useState(10) - local rows, setRows = React.useState(4) + const slots, setSlots = React.useState(10) + const rows, setRows = React.useState(4) React.useEffect(function() - local function updateBackpackSize() - local screenOrientation = playerGui.CurrentScreenOrientation - local viewportSize = GuiService.ViewportDisplaySize + const function updateBackpackSize() + const screenOrientation = playerGui.CurrentScreenOrientation + const viewportSize = GuiService.ViewportDisplaySize if screenOrientation == Enum.ScreenOrientation.Portrait then setSlots(3) @@ -91,8 +91,8 @@ local function Satchel() end updateBackpackSize() - local viewportSignal = GuiService:GetPropertyChangedSignal("ViewportDisplaySize"):Connect(updateBackpackSize) - local orientationSignal = + const viewportSignal = GuiService:GetPropertyChangedSignal("ViewportDisplaySize"):Connect(updateBackpackSize) + const orientationSignal = playerGui:GetPropertyChangedSignal("CurrentScreenOrientation"):Connect(updateBackpackSize) return function() diff --git a/src/Components/App.luau b/src/Components/App.luau index e8983dd4..d0021e2e 100644 --- a/src/Components/App.luau +++ b/src/Components/App.luau @@ -1,19 +1,19 @@ --!strict -local React = require("../../react") +const React = require("../../react") -local Backpack = require("./Backpack") -local HotbarHint = require("./HotbarHint") -local InventoryHint = require("./InventoryHint") +const Backpack = require("./Backpack") +const HotbarHint = require("./HotbarHint") +const InventoryHint = require("./InventoryHint") -local InventoryBindings = script.Parent.Parent.Bindings.InventoryContext -local RemoveFromHotbarGamepadKeyCode = InventoryBindings.RemoveFromHotbarAction.GamepadBinding.KeyCode -local SelectSwapGamepadKeyCode = InventoryBindings.SelectSwapAction.GamepadBinding.KeyCode -local CloseInventoryGamepadKeyCode = InventoryBindings.CloseInventoryAction.GamepadBinding.KeyCode +const InventoryBindings = script.Parent.Parent.Bindings.InventoryContext +const RemoveFromHotbarGamepadKeyCode = InventoryBindings.RemoveFromHotbarAction.GamepadBinding.KeyCode +const SelectSwapGamepadKeyCode = InventoryBindings.SelectSwapAction.GamepadBinding.KeyCode +const CloseInventoryGamepadKeyCode = InventoryBindings.CloseInventoryAction.GamepadBinding.KeyCode -local HotbarBindings = script.Parent.Parent.Bindings.HotbarContext -local SlotLeftGamepadKeyCode = HotbarBindings.SlotLeftAction.GamepadBinding.KeyCode -local SlotRightGamepadKeyCode = HotbarBindings.SlotRightAction.GamepadBinding.KeyCode +const HotbarBindings = script.Parent.Parent.Bindings.HotbarContext +const SlotLeftGamepadKeyCode = HotbarBindings.SlotLeftAction.GamepadBinding.KeyCode +const SlotRightGamepadKeyCode = HotbarBindings.SlotRightAction.GamepadBinding.KeyCode export type Props = { forceGamepadHintVisible: boolean?, @@ -24,9 +24,9 @@ export type Props = { opened: boolean?, } -local function App(props: Props) - local backpackSize, setBackpackSize = React.useState(Vector2.zero) - local slotCount = props.slots or 10 +const function App(props: Props) + const backpackSize, setBackpackSize = React.useState(Vector2.zero) + const slotCount = props.slots or 10 local hotbarVisible = props.opened or false diff --git a/src/Components/App.story.luau b/src/Components/App.story.luau index 3f2cd22c..c269962e 100644 --- a/src/Components/App.story.luau +++ b/src/Components/App.story.luau @@ -1,10 +1,10 @@ --!strict -local React = require("../../react") +const React = require("../../react") -local App = require("./App") +const App = require("./App") -local controls = { +const controls = { hintVisible = true, slots = 10, toolName = "Sword", @@ -23,7 +23,7 @@ return { summary = "Hotbar and inventory, including hints for gamepad controls.", controls = controls, story = function(props: Props) - local tool = Instance.new("Tool") + const tool = Instance.new("Tool") tool.Name = props.controls.toolName tool.TextureId = props.controls.toolImage tool.ToolTip = props.controls.toolTooltip diff --git a/src/Components/Backpack.luau b/src/Components/Backpack.luau index de54a11f..57d3962b 100644 --- a/src/Components/Backpack.luau +++ b/src/Components/Backpack.luau @@ -1,9 +1,9 @@ --!strict -local React = require("../../react") +const React = require("../../react") -local Hotbar = require("./Hotbar") -local Inventory = require("./Inventory") +const Hotbar = require("./Hotbar") +const Inventory = require("./Inventory") export type Props = { forceKeyboardHintVisible: boolean?, @@ -14,13 +14,13 @@ export type Props = { onAbsoluteSizeChanged: ((Vector2) -> ())?, } -local function Backpack(props: Props) - local opened = props.opened or false - local slots = props.slots or 10 +const function Backpack(props: Props) + const opened = props.opened or false + const slots = props.slots or 10 -- Items at indices 1..slots are hotbar; items above slots are inventory. - local hotbarItems: { [number]: Tool | HopperBin } = {} - local inventoryItems: { [number]: Tool | HopperBin } = {} + const hotbarItems: { [number]: Tool | HopperBin } = {} + const inventoryItems: { [number]: Tool | HopperBin } = {} if props.items then for index, item in props.items do if item and index > 0 and index <= slots then diff --git a/src/Components/Backpack.story.luau b/src/Components/Backpack.story.luau index d4fbced4..93fa8f06 100644 --- a/src/Components/Backpack.story.luau +++ b/src/Components/Backpack.story.luau @@ -1,10 +1,10 @@ --!strict -local React = require("../../react") +const React = require("../../react") -local Backpack = require("./Backpack") +const Backpack = require("./Backpack") -local controls = { +const controls = { slots = 10, toolName = "Sword", toolImage = "rbxasset://Textures/Sword128.png", @@ -22,7 +22,7 @@ return { summary = "Backpack that holds the hotbar and inventory", controls = controls, story = function(props: Props) - local tool = Instance.new("Tool") + const tool = Instance.new("Tool") tool.Name = props.controls.toolName tool.TextureId = props.controls.toolImage tool.ToolTip = props.controls.toolTooltip diff --git a/src/Components/Hotbar.luau b/src/Components/Hotbar.luau index 30f20352..6643ce65 100644 --- a/src/Components/Hotbar.luau +++ b/src/Components/Hotbar.luau @@ -1,8 +1,8 @@ --!strict -local React = require("../../react") +const React = require("../../react") -local Slot = require("./Slot") +const Slot = require("./Slot") export type Props = { forceKeyboardHintVisible: boolean?, @@ -11,15 +11,15 @@ export type Props = { opened: boolean?, } -local function Hotbar(props: Props) - local slotCount = props.slots or 10 +const function Hotbar(props: Props) + const slotCount = props.slots or 10 - local children: any = {} + const children: any = {} -- Create hotbar slots for order = 1, slotCount do - local item = props.items and props.items[order] - local slotUnlocked = props.opened and item ~= nil + const item = props.items and props.items[order] + const slotUnlocked = props.opened and item ~= nil -- Only show slots if the hotbar is opened or if there is a tool in the slot if props.opened or item then diff --git a/src/Components/Hotbar.story.luau b/src/Components/Hotbar.story.luau index 0e01bda9..794f17f3 100644 --- a/src/Components/Hotbar.story.luau +++ b/src/Components/Hotbar.story.luau @@ -1,10 +1,10 @@ --!strict -local React = require("../../react") +const React = require("../../react") -local Hotbar = require("./Hotbar") +const Hotbar = require("./Hotbar") -local controls = { +const controls = { slots = 10, toolName = "Sword", toolImage = "rbxasset://Textures/Sword128.png", @@ -21,7 +21,7 @@ return { summary = "Hotbar on the bottom of the screen that shows equipped tools and hints for equipping", controls = controls, story = function(props: Props) - local tool = Instance.new("Tool") + const tool = Instance.new("Tool") tool.Name = props.controls.toolName tool.TextureId = props.controls.toolImage tool.ToolTip = props.controls.tooltipText diff --git a/src/Components/HotbarHint.luau b/src/Components/HotbarHint.luau index 7ef580bc..5a51de55 100644 --- a/src/Components/HotbarHint.luau +++ b/src/Components/HotbarHint.luau @@ -1,8 +1,8 @@ --!strict -local UserInputService = game:GetService("UserInputService") +const UserInputService = game:GetService("UserInputService") -local React = require("../../react") +const React = require("../../react") export type Props = { keyCode: Enum.KeyCode, @@ -11,7 +11,7 @@ export type Props = { visible: boolean?, } -local function HotbarHint(props: Props) +const function HotbarHint(props: Props) local tags = "HotbarHint" if props.forceVisible then tags = tags .. " Visible" diff --git a/src/Components/HotbarHint.story.luau b/src/Components/HotbarHint.story.luau index 16654a56..6d83959d 100644 --- a/src/Components/HotbarHint.story.luau +++ b/src/Components/HotbarHint.story.luau @@ -1,8 +1,8 @@ --!strict -local React = require("../../react") +const React = require("../../react") -local HotbarHint = require("./HotbarHint") +const HotbarHint = require("./HotbarHint") return { name = "Hotbar Hint", diff --git a/src/Components/Inventory.luau b/src/Components/Inventory.luau index 899236d8..a4d903ac 100644 --- a/src/Components/Inventory.luau +++ b/src/Components/Inventory.luau @@ -1,9 +1,9 @@ --!strict -local React = require("../../react") +const React = require("../../react") -local Searchbar = require("./Searchbar") -local Slot = require("./Slot") +const Searchbar = require("./Searchbar") +const Slot = require("./Slot") export type Props = { width: number?, @@ -12,12 +12,12 @@ export type Props = { opened: boolean?, } -local function Inventory(props: Props) - local width = props.width or 0 - local rows = props.rows or 4 - local height = rows * 65 - 5 +const function Inventory(props: Props) + const width = props.width or 0 + const rows = props.rows or 4 + const height = rows * 65 - 5 - local children: any = {} + const children: any = {} -- Create inventory slots if props.items then diff --git a/src/Components/Inventory.story.luau b/src/Components/Inventory.story.luau index ff1dd7cf..cbdd7cc6 100644 --- a/src/Components/Inventory.story.luau +++ b/src/Components/Inventory.story.luau @@ -1,10 +1,10 @@ --!strict -local React = require("../../react") +const React = require("../../react") -local Inventory = require("./Inventory") +const Inventory = require("./Inventory") -local controls = { +const controls = { toolName = "Sword", toolImage = "rbxasset://Textures/Sword128.png", tooltipText = "A classic sword", @@ -19,7 +19,7 @@ return { summary = "Toggleable inventory for displaying items not in the hotbar", controls = controls, story = function(props: Props) - local tool = Instance.new("Tool") + const tool = Instance.new("Tool") tool.Name = props.controls.toolName tool.TextureId = props.controls.toolImage tool.ToolTip = props.controls.tooltipText diff --git a/src/Components/InventoryHint.luau b/src/Components/InventoryHint.luau index 711c1c10..ccc391b7 100644 --- a/src/Components/InventoryHint.luau +++ b/src/Components/InventoryHint.luau @@ -1,8 +1,8 @@ --!strict -local UserInputService = game:GetService("UserInputService") +const UserInputService = game:GetService("UserInputService") -local React = require("../../react") +const React = require("../../react") export type Props = { keyCode: Enum.KeyCode, @@ -11,7 +11,7 @@ export type Props = { order: number?, } -local function InventoryHint(props: Props) +const function InventoryHint(props: Props) local tags = "InventoryHint" if props.forceVisible then tags = tags .. " Visible" diff --git a/src/Components/InventoryHint.story.luau b/src/Components/InventoryHint.story.luau index 3a8f58bc..97f6eb9d 100644 --- a/src/Components/InventoryHint.story.luau +++ b/src/Components/InventoryHint.story.luau @@ -1,10 +1,10 @@ --!strict -local React = require("../../react") +const React = require("../../react") -local InventoryHint = require("./InventoryHint") +const InventoryHint = require("./InventoryHint") -local controls = { +const controls = { text = "Remove from Hotbar", } diff --git a/src/Components/Satchel.storybook.luau b/src/Components/Satchel.storybook.luau index ee5c2dd1..21cb908e 100644 --- a/src/Components/Satchel.storybook.luau +++ b/src/Components/Satchel.storybook.luau @@ -1,9 +1,9 @@ --!strict -local React = require("../../react") -local ReactRoblox = require("../../react-roblox") +const React = require("../../react") +const ReactRoblox = require("../../react-roblox") -local DESIGN_SHEET = script.Parent.Parent.Design.SatchelStyleSheet +const DESIGN_SHEET = script.Parent.Parent.Design.SatchelStyleSheet return { name = "Satchel", diff --git a/src/Components/Searchbar.luau b/src/Components/Searchbar.luau index ed62b3fc..e6694f87 100644 --- a/src/Components/Searchbar.luau +++ b/src/Components/Searchbar.luau @@ -1,13 +1,13 @@ --!strict -local React = require("../../react") +const React = require("../../react") export type Props = { size: UDim2?, } -local function Searchbar(props: Props) - local text, setText = React.useState("") +const function Searchbar(props: Props) + const text, setText = React.useState("") return React.createElement("TextBox", { Size = props.size, diff --git a/src/Components/Searchbar.story.luau b/src/Components/Searchbar.story.luau index 73c90013..a8be4580 100644 --- a/src/Components/Searchbar.story.luau +++ b/src/Components/Searchbar.story.luau @@ -1,8 +1,8 @@ --!strict -local React = require("../../react") +const React = require("../../react") -local Searchbar = require("./Searchbar") +const Searchbar = require("./Searchbar") return { summary = "Search for items in the inventory", diff --git a/src/Components/Slot.luau b/src/Components/Slot.luau index 3f68ef9b..24730488 100644 --- a/src/Components/Slot.luau +++ b/src/Components/Slot.luau @@ -1,8 +1,8 @@ --!strict -local React = require("../../react") +const React = require("../../react") -local Tooltip = require("./Tooltip") +const Tooltip = require("./Tooltip") export type Props = { item: (Tool | HopperBin)?, @@ -13,16 +13,16 @@ export type Props = { order: number?, } -local function Slot(props: Props) - local item = props.item - local itemName = item and item.Name - local itemImage = item and item.TextureId - local tooltipText = item and (item:IsA("Tool") and item.ToolTip or "") +const function Slot(props: Props) + const item = props.item + const itemName = item and item.Name + const itemImage = item and item.TextureId + const tooltipText = item and (item:IsA("Tool") and item.ToolTip or "") local equipped, setEquipped = React.useState(props.equipped or false) -- Only show numbers 1-10 for hints and show 0 for the 10th slot - local order = props.order or 1 + const order = props.order or 1 local slotNumber = "" if order >= 1 and order < 10 then slotNumber = tostring(order) @@ -30,7 +30,7 @@ local function Slot(props: Props) slotNumber = "0" end - local hintVisible = props.hint == true and props.forceHintVisible + const hintVisible = props.hint == true and props.forceHintVisible -- Generate tags based on state local tags = "Slot" diff --git a/src/Components/Slot.story.luau b/src/Components/Slot.story.luau index c4e1c4e8..da4b1b85 100644 --- a/src/Components/Slot.story.luau +++ b/src/Components/Slot.story.luau @@ -1,10 +1,10 @@ --!strict -local React = require("../../react") +const React = require("../../react") -local Slot = require("./Slot") +const Slot = require("./Slot") -local controls = { +const controls = { toolName = "Sword", toolImage = "rbxasset://Textures/Sword128.png", toolTooltip = "A classic sword", @@ -22,7 +22,7 @@ return { summary = "Slot representing a single item in the hotbar or inventory, showing the tool and hints for equipping", controls = controls, story = function(props: Props) - local tool = Instance.new("Tool") + const tool = Instance.new("Tool") tool.Name = props.controls.toolName tool.TextureId = props.controls.toolImage tool.ToolTip = props.controls.toolTooltip diff --git a/src/Components/Tooltip.luau b/src/Components/Tooltip.luau index 68d2ecc2..4a18198e 100644 --- a/src/Components/Tooltip.luau +++ b/src/Components/Tooltip.luau @@ -1,12 +1,12 @@ --!strict -local React = require("../../react") +const React = require("../../react") export type Props = { text: string?, } -local function Tooltip(props: Props) +const function Tooltip(props: Props) -- Hide tooltip if there is no text if not props.text or props.text == "" then return diff --git a/src/Components/Tooltip.story.luau b/src/Components/Tooltip.story.luau index 8d6bc0af..b35ca556 100644 --- a/src/Components/Tooltip.story.luau +++ b/src/Components/Tooltip.story.luau @@ -1,10 +1,10 @@ --!strict -local React = require("../../react") +const React = require("../../react") -local Tooltip = require("./Tooltip") +const Tooltip = require("./Tooltip") -local controls = { +const controls = { text = "I'm a tooltip!", } diff --git a/src/CoreGuiWarn.client.luau b/src/CoreGuiWarn.client.luau index 88f12e56..b56acf88 100644 --- a/src/CoreGuiWarn.client.luau +++ b/src/CoreGuiWarn.client.luau @@ -1,8 +1,8 @@ --!strict -local StarterGui = game:GetService("StarterGui") +const StarterGui = game:GetService("StarterGui") -local Satchel = require("./") +const Satchel = require("./") task.spawn(function() while task.wait(1) do diff --git a/src/TopbarIcon.client.luau b/src/TopbarIcon.client.luau index ec5f8ae4..000ec9db 100644 --- a/src/TopbarIcon.client.luau +++ b/src/TopbarIcon.client.luau @@ -1,9 +1,9 @@ --!strict -local Icon = require("../topbarplus") -local Satchel = require("./") +const Icon = require("../topbarplus") +const Satchel = require("./") -local icon = Icon.new() +const icon = Icon.new() icon:setName("SatchelInventory") icon:modifyTheme({ { "IconLabelContainer", "TargetWidth", 0 }, -- Force minimum width diff --git a/src/init.luau b/src/init.luau index 70da5fa3..617d3161 100644 --- a/src/init.luau +++ b/src/init.luau @@ -1,6 +1,6 @@ --!strict -local bindableEvents = script.BindableEvents +const bindableEvents = script.BindableEvents return { -- Functions diff --git a/tests/SatchelEnabled.client.luau b/tests/SatchelEnabled.client.luau index eaa36f35..d6dd5df6 100644 --- a/tests/SatchelEnabled.client.luau +++ b/tests/SatchelEnabled.client.luau @@ -1,11 +1,11 @@ --!strict -local StarterGui = game:GetService("StarterGui") +const StarterGui = game:GetService("StarterGui") -local Icon = require("./Satchel/Packages/topbarplus") -local Satchel = require("./Satchel") +const Icon = require("./Satchel/Packages/topbarplus") +const Satchel = require("./Satchel") -local icon = Icon.new() +const icon = Icon.new() icon:modifyTheme({ { "IconLabelContainer", "TargetWidth", 0 }, -- Force minimum width { "IconLabel", "AutoLocalize", false }, -- Don't translate font icon diff --git a/tests/SwitchTheme.client.luau b/tests/SwitchTheme.client.luau index 9e96d806..d45b8bc1 100644 --- a/tests/SwitchTheme.client.luau +++ b/tests/SwitchTheme.client.luau @@ -1,9 +1,9 @@ --!strict -local Icon = require("./Satchel/Packages/topbarplus") -local Satchel = require("./Satchel") +const Icon = require("./Satchel/Packages/topbarplus") +const Satchel = require("./Satchel") -local icon = Icon.new() +const icon = Icon.new() icon:modifyTheme({ { "IconLabelContainer", "TargetWidth", 0 }, -- Force minimum width { "IconLabel", "AutoLocalize", false }, -- Don't translate font icon From 3c68f9562b54617f18b3b818a336185aa036a75e Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 11 Apr 2026 19:24:39 -0700 Subject: [PATCH 179/186] Switch to haedrix for React Luau Signed-off-by: Ryan Luu --- wally.lock | 72 +++++++++++++++++++++++++++++++----------------------- wally.toml | 4 +-- 2 files changed, 43 insertions(+), 33 deletions(-) diff --git a/wally.lock b/wally.lock index 55738e11..eecaea7d 100644 --- a/wally.lock +++ b/wally.lock @@ -2,6 +2,46 @@ # It is not intended for manual editing. registry = "test" +[[package]] +name = "evaera/promise" +version = "4.0.0" +dependencies = [] + +[[package]] +name = "haedrix/react" +version = "17.3.8" +dependencies = [["LuauPolyfill", "jsdotlua/luau-polyfill@1.2.7"], ["ReactGlobals", "haedrix/react-globals@17.3.8"], ["Shared", "haedrix/shared@17.3.8"]] + +[[package]] +name = "haedrix/react-globals" +version = "17.3.8" +dependencies = [["SafeFlags", "haedrix/safe-flags@0.1.1"]] + +[[package]] +name = "haedrix/react-reconciler" +version = "17.3.8" +dependencies = [["LuauPolyfill", "jsdotlua/luau-polyfill@1.2.7"], ["Promise", "evaera/promise@4.0.0"], ["React", "haedrix/react@17.3.8"], ["ReactGlobals", "haedrix/react-globals@17.3.8"], ["SafeFlags", "haedrix/safe-flags@0.1.1"], ["Scheduler", "haedrix/scheduler@17.3.8"], ["Shared", "haedrix/shared@17.3.8"]] + +[[package]] +name = "haedrix/react-roblox" +version = "17.3.8" +dependencies = [["LuauPolyfill", "jsdotlua/luau-polyfill@1.2.7"], ["React", "haedrix/react@17.3.8"], ["ReactGlobals", "haedrix/react-globals@17.3.8"], ["ReactReconciler", "haedrix/react-reconciler@17.3.8"], ["Scheduler", "haedrix/scheduler@17.3.8"], ["Shared", "haedrix/shared@17.3.8"]] + +[[package]] +name = "haedrix/safe-flags" +version = "0.1.1" +dependencies = [] + +[[package]] +name = "haedrix/scheduler" +version = "17.3.8" +dependencies = [["LuauPolyfill", "jsdotlua/luau-polyfill@1.2.7"], ["ReactGlobals", "haedrix/react-globals@17.3.8"], ["SafeFlags", "haedrix/safe-flags@0.1.1"], ["Shared", "haedrix/shared@17.3.8"]] + +[[package]] +name = "haedrix/shared" +version = "17.3.8" +dependencies = [["LuauPolyfill", "jsdotlua/luau-polyfill@1.2.7"], ["ReactGlobals", "haedrix/react-globals@17.3.8"], ["SafeFlags", "haedrix/safe-flags@0.1.1"]] + [[package]] name = "jsdotlua/boolean" version = "1.2.7" @@ -42,36 +82,6 @@ name = "jsdotlua/number" version = "1.2.7" dependencies = [] -[[package]] -name = "jsdotlua/promise" -version = "3.5.2" -dependencies = [] - -[[package]] -name = "jsdotlua/react" -version = "17.2.1" -dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["shared", "jsdotlua/shared@17.2.1"]] - -[[package]] -name = "jsdotlua/react-reconciler" -version = "17.2.1" -dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["promise", "jsdotlua/promise@3.5.2"], ["react", "jsdotlua/react@17.2.1"], ["scheduler", "jsdotlua/scheduler@17.2.1"], ["shared", "jsdotlua/shared@17.2.1"]] - -[[package]] -name = "jsdotlua/react-roblox" -version = "17.2.1" -dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["react", "jsdotlua/react@17.2.1"], ["react-reconciler", "jsdotlua/react-reconciler@17.2.1"], ["scheduler", "jsdotlua/scheduler@17.2.1"], ["shared", "jsdotlua/shared@17.2.1"]] - -[[package]] -name = "jsdotlua/scheduler" -version = "17.2.1" -dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["shared", "jsdotlua/shared@17.2.1"]] - -[[package]] -name = "jsdotlua/shared" -version = "17.2.1" -dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"]] - [[package]] name = "jsdotlua/string" version = "1.2.7" @@ -90,7 +100,7 @@ dependencies = [["collections", "jsdotlua/collections@1.2.7"]] [[package]] name = "ryanlua/satchel" version = "2.0.0" -dependencies = [["react", "jsdotlua/react@17.2.1"], ["react-roblox", "jsdotlua/react-roblox@17.2.1"], ["topbarplus", "ryanlua/topbarplus@1.0.1"]] +dependencies = [["react", "haedrix/react@17.3.8"], ["react-roblox", "haedrix/react-roblox@17.3.8"], ["topbarplus", "ryanlua/topbarplus@1.0.1"]] [[package]] name = "ryanlua/topbarplus" diff --git a/wally.toml b/wally.toml index 0df25c94..e015ed72 100644 --- a/wally.toml +++ b/wally.toml @@ -12,6 +12,6 @@ exclude = ["**"] include = ["src", "src/**", "wally.toml", "wally.lock", "default.project.json", "LICENSE", "README.md"] [dependencies] -react = "jsdotlua/react@17.2.1" -react-roblox = "jsdotlua/react-roblox@17.2.1" +react = "haedrix/react@17.3.8" +react-roblox = "haedrix/react-roblox@17.3.8" topbarplus = "ryanlua/topbarplus@1.0.1" From ddc7295242b4deb569146430eea9e0f97e6a0b3e Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 11 Apr 2026 20:51:54 -0700 Subject: [PATCH 180/186] Add React DevTools Signed-off-by: Ryan Luu --- src/Client.client.luau | 10 ++++++++-- wally.lock | 32 +++++++++++++++++++++++++++++++- wally.toml | 2 ++ 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/Client.client.luau b/src/Client.client.luau index 8d28b111..1868091e 100644 --- a/src/Client.client.luau +++ b/src/Client.client.luau @@ -6,8 +6,14 @@ const RunService = game:GetService("RunService") const StarterGui = game:GetService("StarterGui") const UserInputService = game:GetService("UserInputService") --- selene: allow(global_usage) -_G.__DEV__ = RunService:IsStudio() +const ReactGlobals = require("../react-globals") + +-- Enable Dev Mode and React DevTools in Studio +if RunService:IsStudio() then + ReactGlobals.__DEV__ = true + ReactGlobals.__PROFILE__ = true + require("../react-devtools") +end const React = require("../react") const ReactRoblox = require("../react-roblox") diff --git a/wally.lock b/wally.lock index eecaea7d..1beb3f25 100644 --- a/wally.lock +++ b/wally.lock @@ -12,11 +12,36 @@ name = "haedrix/react" version = "17.3.8" dependencies = [["LuauPolyfill", "jsdotlua/luau-polyfill@1.2.7"], ["ReactGlobals", "haedrix/react-globals@17.3.8"], ["Shared", "haedrix/shared@17.3.8"]] +[[package]] +name = "haedrix/react-debug-tools" +version = "17.3.8" +dependencies = [["LuauPolyfill", "jsdotlua/luau-polyfill@1.2.7"], ["ReactGlobals", "haedrix/react-globals@17.3.8"], ["ReactReconciler", "haedrix/react-reconciler@17.3.8"], ["Shared", "haedrix/shared@17.3.8"]] + +[[package]] +name = "haedrix/react-devtools" +version = "17.3.8" +dependencies = [["ReactDevtoolsCore", "haedrix/react-devtools-core@17.3.8"]] + +[[package]] +name = "haedrix/react-devtools-core" +version = "17.3.8" +dependencies = [["LuauPolyfill", "jsdotlua/luau-polyfill@1.2.7"], ["ReactDevtoolsShared", "haedrix/react-devtools-shared@17.3.8"], ["ReactGlobals", "haedrix/react-globals@17.3.8"], ["ReactTelemetry", "haedrix/react-telemetry@17.3.8"], ["SafeFlags", "haedrix/safe-flags@0.1.1"]] + +[[package]] +name = "haedrix/react-devtools-shared" +version = "17.3.8" +dependencies = [["LuauPolyfill", "jsdotlua/luau-polyfill@1.2.7"], ["React", "haedrix/react@17.3.8"], ["ReactDebugTools", "haedrix/react-debug-tools@17.3.8"], ["ReactGlobals", "haedrix/react-globals@17.3.8"], ["ReactIs", "haedrix/react-is@17.3.8"], ["ReactReconciler", "haedrix/react-reconciler@17.3.8"], ["ReactRoblox", "haedrix/react-roblox@17.3.8"], ["Shared", "haedrix/shared@17.3.8"]] + [[package]] name = "haedrix/react-globals" version = "17.3.8" dependencies = [["SafeFlags", "haedrix/safe-flags@0.1.1"]] +[[package]] +name = "haedrix/react-is" +version = "17.3.8" +dependencies = [["ReactGlobals", "haedrix/react-globals@17.3.8"], ["SafeFlags", "haedrix/safe-flags@0.1.1"], ["Shared", "haedrix/shared@17.3.8"]] + [[package]] name = "haedrix/react-reconciler" version = "17.3.8" @@ -27,6 +52,11 @@ name = "haedrix/react-roblox" version = "17.3.8" dependencies = [["LuauPolyfill", "jsdotlua/luau-polyfill@1.2.7"], ["React", "haedrix/react@17.3.8"], ["ReactGlobals", "haedrix/react-globals@17.3.8"], ["ReactReconciler", "haedrix/react-reconciler@17.3.8"], ["Scheduler", "haedrix/scheduler@17.3.8"], ["Shared", "haedrix/shared@17.3.8"]] +[[package]] +name = "haedrix/react-telemetry" +version = "17.3.8" +dependencies = [["LuauPolyfill", "jsdotlua/luau-polyfill@1.2.7"], ["ReactGlobals", "haedrix/react-globals@17.3.8"], ["SafeFlags", "haedrix/safe-flags@0.1.1"]] + [[package]] name = "haedrix/safe-flags" version = "0.1.1" @@ -100,7 +130,7 @@ dependencies = [["collections", "jsdotlua/collections@1.2.7"]] [[package]] name = "ryanlua/satchel" version = "2.0.0" -dependencies = [["react", "haedrix/react@17.3.8"], ["react-roblox", "haedrix/react-roblox@17.3.8"], ["topbarplus", "ryanlua/topbarplus@1.0.1"]] +dependencies = [["react", "haedrix/react@17.3.8"], ["react-devtools", "haedrix/react-devtools@17.3.8"], ["react-globals", "haedrix/react-globals@17.3.8"], ["react-roblox", "haedrix/react-roblox@17.3.8"], ["topbarplus", "ryanlua/topbarplus@1.0.1"]] [[package]] name = "ryanlua/topbarplus" diff --git a/wally.toml b/wally.toml index e015ed72..dd6b2cca 100644 --- a/wally.toml +++ b/wally.toml @@ -13,5 +13,7 @@ include = ["src", "src/**", "wally.toml", "wally.lock", "default.project.json", [dependencies] react = "haedrix/react@17.3.8" +react-devtools = "haedrix/react-devtools@17.3.8" +react-globals = "haedrix/react-globals@17.3.8" react-roblox = "haedrix/react-roblox@17.3.8" topbarplus = "ryanlua/topbarplus@1.0.1" From 27985e3b7d9810ff2ba2fc6a81111dac3f4a0cca Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 11 Apr 2026 21:14:23 -0700 Subject: [PATCH 181/186] Move require into studio Signed-off-by: Ryan Luu --- src/Client.client.luau | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Client.client.luau b/src/Client.client.luau index 1868091e..97c883d0 100644 --- a/src/Client.client.luau +++ b/src/Client.client.luau @@ -6,10 +6,9 @@ const RunService = game:GetService("RunService") const StarterGui = game:GetService("StarterGui") const UserInputService = game:GetService("UserInputService") -const ReactGlobals = require("../react-globals") - -- Enable Dev Mode and React DevTools in Studio if RunService:IsStudio() then + const ReactGlobals = require("../react-globals") ReactGlobals.__DEV__ = true ReactGlobals.__PROFILE__ = true require("../react-devtools") From 431cb6efc21164b6c3234cbee0163d88806f831b Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 13 Apr 2026 16:24:48 -0700 Subject: [PATCH 182/186] Remove strict typing from React React Luau doesn't like strict typing a lot. Removed until typing React is better Signed-off-by: Ryan Luu --- src/Components/App.luau | 2 -- src/Components/App.story.luau | 1 - src/Components/Backpack.luau | 1 - src/Components/Backpack.story.luau | 1 - src/Components/Hotbar.luau | 1 - src/Components/Hotbar.story.luau | 1 - src/Components/HotbarHint.luau | 1 - src/Components/HotbarHint.story.luau | 1 - src/Components/Inventory.luau | 1 - src/Components/Inventory.story.luau | 1 - src/Components/InventoryHint.luau | 1 - src/Components/InventoryHint.story.luau | 1 - src/Components/Satchel.storybook.luau | 1 - src/Components/Searchbar.luau | 1 - src/Components/Searchbar.story.luau | 1 - src/Components/Slot.luau | 1 - src/Components/Slot.story.luau | 1 - src/Components/Tooltip.luau | 1 - src/Components/Tooltip.story.luau | 1 - 19 files changed, 20 deletions(-) diff --git a/src/Components/App.luau b/src/Components/App.luau index d0021e2e..39d1285f 100644 --- a/src/Components/App.luau +++ b/src/Components/App.luau @@ -1,5 +1,3 @@ ---!strict - const React = require("../../react") const Backpack = require("./Backpack") diff --git a/src/Components/App.story.luau b/src/Components/App.story.luau index c269962e..a1c60ae0 100644 --- a/src/Components/App.story.luau +++ b/src/Components/App.story.luau @@ -1,4 +1,3 @@ ---!strict const React = require("../../react") diff --git a/src/Components/Backpack.luau b/src/Components/Backpack.luau index 57d3962b..906328d6 100644 --- a/src/Components/Backpack.luau +++ b/src/Components/Backpack.luau @@ -1,4 +1,3 @@ ---!strict const React = require("../../react") diff --git a/src/Components/Backpack.story.luau b/src/Components/Backpack.story.luau index 93fa8f06..35934a65 100644 --- a/src/Components/Backpack.story.luau +++ b/src/Components/Backpack.story.luau @@ -1,4 +1,3 @@ ---!strict const React = require("../../react") diff --git a/src/Components/Hotbar.luau b/src/Components/Hotbar.luau index 6643ce65..779245a6 100644 --- a/src/Components/Hotbar.luau +++ b/src/Components/Hotbar.luau @@ -1,4 +1,3 @@ ---!strict const React = require("../../react") diff --git a/src/Components/Hotbar.story.luau b/src/Components/Hotbar.story.luau index 794f17f3..018e50c0 100644 --- a/src/Components/Hotbar.story.luau +++ b/src/Components/Hotbar.story.luau @@ -1,4 +1,3 @@ ---!strict const React = require("../../react") diff --git a/src/Components/HotbarHint.luau b/src/Components/HotbarHint.luau index 5a51de55..65ee1600 100644 --- a/src/Components/HotbarHint.luau +++ b/src/Components/HotbarHint.luau @@ -1,4 +1,3 @@ ---!strict const UserInputService = game:GetService("UserInputService") diff --git a/src/Components/HotbarHint.story.luau b/src/Components/HotbarHint.story.luau index 6d83959d..829fa10a 100644 --- a/src/Components/HotbarHint.story.luau +++ b/src/Components/HotbarHint.story.luau @@ -1,4 +1,3 @@ ---!strict const React = require("../../react") diff --git a/src/Components/Inventory.luau b/src/Components/Inventory.luau index a4d903ac..aac090cf 100644 --- a/src/Components/Inventory.luau +++ b/src/Components/Inventory.luau @@ -1,4 +1,3 @@ ---!strict const React = require("../../react") diff --git a/src/Components/Inventory.story.luau b/src/Components/Inventory.story.luau index cbdd7cc6..f245e935 100644 --- a/src/Components/Inventory.story.luau +++ b/src/Components/Inventory.story.luau @@ -1,4 +1,3 @@ ---!strict const React = require("../../react") diff --git a/src/Components/InventoryHint.luau b/src/Components/InventoryHint.luau index ccc391b7..d50c6081 100644 --- a/src/Components/InventoryHint.luau +++ b/src/Components/InventoryHint.luau @@ -1,4 +1,3 @@ ---!strict const UserInputService = game:GetService("UserInputService") diff --git a/src/Components/InventoryHint.story.luau b/src/Components/InventoryHint.story.luau index 97f6eb9d..60ae6f41 100644 --- a/src/Components/InventoryHint.story.luau +++ b/src/Components/InventoryHint.story.luau @@ -1,4 +1,3 @@ ---!strict const React = require("../../react") diff --git a/src/Components/Satchel.storybook.luau b/src/Components/Satchel.storybook.luau index 21cb908e..82e2fb30 100644 --- a/src/Components/Satchel.storybook.luau +++ b/src/Components/Satchel.storybook.luau @@ -1,4 +1,3 @@ ---!strict const React = require("../../react") const ReactRoblox = require("../../react-roblox") diff --git a/src/Components/Searchbar.luau b/src/Components/Searchbar.luau index e6694f87..2bdc7968 100644 --- a/src/Components/Searchbar.luau +++ b/src/Components/Searchbar.luau @@ -1,4 +1,3 @@ ---!strict const React = require("../../react") diff --git a/src/Components/Searchbar.story.luau b/src/Components/Searchbar.story.luau index a8be4580..8fdadd2f 100644 --- a/src/Components/Searchbar.story.luau +++ b/src/Components/Searchbar.story.luau @@ -1,4 +1,3 @@ ---!strict const React = require("../../react") diff --git a/src/Components/Slot.luau b/src/Components/Slot.luau index 24730488..53d2d08b 100644 --- a/src/Components/Slot.luau +++ b/src/Components/Slot.luau @@ -1,4 +1,3 @@ ---!strict const React = require("../../react") diff --git a/src/Components/Slot.story.luau b/src/Components/Slot.story.luau index da4b1b85..287b526e 100644 --- a/src/Components/Slot.story.luau +++ b/src/Components/Slot.story.luau @@ -1,4 +1,3 @@ ---!strict const React = require("../../react") diff --git a/src/Components/Tooltip.luau b/src/Components/Tooltip.luau index 4a18198e..f43b65f6 100644 --- a/src/Components/Tooltip.luau +++ b/src/Components/Tooltip.luau @@ -1,4 +1,3 @@ ---!strict const React = require("../../react") diff --git a/src/Components/Tooltip.story.luau b/src/Components/Tooltip.story.luau index b35ca556..fb96a78c 100644 --- a/src/Components/Tooltip.story.luau +++ b/src/Components/Tooltip.story.luau @@ -1,4 +1,3 @@ ---!strict const React = require("../../react") From 71834a495fde831bd505659ac6c93d6d3c09211f Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 13 Apr 2026 22:06:20 -0700 Subject: [PATCH 183/186] Fix types Signed-off-by: Ryan Luu --- src/Api/getEnabled.luau | 4 ++-- src/Api/getTheme.luau | 3 +-- src/Api/getTopbarIcon.luau | 4 ++-- src/Api/setEnabled.luau | 4 ++-- src/Api/setTheme.luau | 9 +++++---- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Api/getEnabled.luau b/src/Api/getEnabled.luau index 8a6b3d35..a430933a 100644 --- a/src/Api/getEnabled.luau +++ b/src/Api/getEnabled.luau @@ -3,9 +3,9 @@ const Players = game:GetService("Players") const RunService = game:GetService("RunService") -const player = Players.LocalPlayer +const player = Players.LocalPlayer :: Player const playerGui = player:WaitForChild("PlayerGui") -const screenGui = playerGui:WaitForChild("SatchelGui") +const screenGui = playerGui:WaitForChild("SatchelGui") :: ScreenGui const function getEnabled(): boolean assert(RunService:IsClient(), "getEnabled can only be called on the client") diff --git a/src/Api/getTheme.luau b/src/Api/getTheme.luau index 899a2714..4096389b 100644 --- a/src/Api/getTheme.luau +++ b/src/Api/getTheme.luau @@ -7,8 +7,7 @@ const currentStyleSheet = script.Parent.Parent.Design.SatchelStyleSheet const function getTheme(): StyleSheet assert(RunService:IsClient(), "getTheme can only be called on the client") - const currentTheme = currentStyleSheet:FindFirstChildWhichIsA("StyleDerive").StyleSheet - return currentTheme + return currentStyleSheet:FindFirstChildOfClass("StyleDerive").StyleSheet :: StyleSheet end return getTheme diff --git a/src/Api/getTopbarIcon.luau b/src/Api/getTopbarIcon.luau index d6ef2784..c3a62a98 100644 --- a/src/Api/getTopbarIcon.luau +++ b/src/Api/getTopbarIcon.luau @@ -4,10 +4,10 @@ const RunService = game:GetService("RunService") const TopbarPlus = require("../../topbarplus") -const function getTopbarIcon(): TopbarPlus.Icon? +const function getTopbarIcon(): TopbarPlus.Icon assert(RunService:IsClient(), "getTopbarIcon can only be called on the client") - return TopbarPlus.getIcon("SatchelInventory") + return TopbarPlus.getIcon("SatchelInventory") :: TopbarPlus.Icon end return getTopbarIcon diff --git a/src/Api/setEnabled.luau b/src/Api/setEnabled.luau index 6090abf6..cecffe53 100644 --- a/src/Api/setEnabled.luau +++ b/src/Api/setEnabled.luau @@ -5,9 +5,9 @@ const RunService = game:GetService("RunService") const getTopbarIcon = require("./getTopbarIcon") -const player = Players.LocalPlayer +const player = Players.LocalPlayer :: Player const playerGui = player:WaitForChild("PlayerGui") -const screenGui = playerGui:WaitForChild("SatchelGui") +const screenGui = playerGui:WaitForChild("SatchelGui") :: ScreenGui const function setEnabled(enabled: boolean): () assert(RunService:IsClient(), "setEnabled can only be called on the client") diff --git a/src/Api/setTheme.luau b/src/Api/setTheme.luau index afc17c42..36a11dc5 100644 --- a/src/Api/setTheme.luau +++ b/src/Api/setTheme.luau @@ -4,13 +4,14 @@ const RunService = game:GetService("RunService") const bindableEvents = script.Parent.Parent.BindableEvents const styleSheets = script.Parent.Parent.Design -const currentTheme = styleSheets.SatchelStyleSheet:FindFirstChildWhichIsA("StyleDerive") +const currentTheme = styleSheets.SatchelStyleSheet:FindFirstChildOfClass("StyleDerive") :: StyleDerive --- TODO: Add autocomplete for default themes -const function setTheme(theme: string | StyleSheet) +type DefaultThemes = "DefaultTheme" | "LegacyTheme" + +const function setTheme(theme: DefaultThemes | StyleSheet) assert(RunService:IsClient(), "setTheme can only be called on the client") - const newTheme = if typeof(theme) == "string" then styleSheets:WaitForChild(theme) else theme + const newTheme: StyleSheet = if typeof(theme) == "string" then styleSheets:WaitForChild(theme) :: StyleSheet else theme currentTheme.StyleSheet = newTheme bindableEvents.ThemeChanged:Fire(newTheme) From fdc0a4d862c1eb0432b9af4e1d5262696a90c27b Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 13 Apr 2026 22:54:05 -0700 Subject: [PATCH 184/186] Disable strict typing for client Signed-off-by: Ryan Luu --- src/Client.client.luau | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Client.client.luau b/src/Client.client.luau index 97c883d0..01dac264 100644 --- a/src/Client.client.luau +++ b/src/Client.client.luau @@ -1,5 +1,3 @@ ---!strict - const GuiService = game:GetService("GuiService") const Players = game:GetService("Players") const RunService = game:GetService("RunService") @@ -22,8 +20,8 @@ const App = require("./Components/App") const DESIGN_SHEET = script.Parent.Design.SatchelStyleSheet -const player = Players.LocalPlayer -const playerGui = player:WaitForChild("PlayerGui") +const player = Players.LocalPlayer :: Player +const playerGui = player:WaitForChild("PlayerGui") :: PlayerGui StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false) @@ -34,6 +32,7 @@ handle.Parent = playerGui const root = ReactRoblox.createRoot(handle) +@nocheck const function Satchel() -- Open and close backpack based on bindable events const opened, setOpened = React.useState(false) From 73c6853f0c4ae6a565da1982af5a07f8f574cb64 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Tue, 14 Apr 2026 01:01:50 -0700 Subject: [PATCH 185/186] Remove function attribution Signed-off-by: Ryan Luu --- src/Client.client.luau | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Client.client.luau b/src/Client.client.luau index 01dac264..3b6754c5 100644 --- a/src/Client.client.luau +++ b/src/Client.client.luau @@ -32,7 +32,6 @@ handle.Parent = playerGui const root = ReactRoblox.createRoot(handle) -@nocheck const function Satchel() -- Open and close backpack based on bindable events const opened, setOpened = React.useState(false) From 23cbaaf79d05ac330c130f8b69fb7085d30490f7 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Tue, 14 Apr 2026 01:09:24 -0700 Subject: [PATCH 186/186] Add basic backpack logic Signed-off-by: Ryan Luu --- tests/PrintBackpack.client.luau | 67 +++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 tests/PrintBackpack.client.luau diff --git a/tests/PrintBackpack.client.luau b/tests/PrintBackpack.client.luau new file mode 100644 index 00000000..5939f2f9 --- /dev/null +++ b/tests/PrintBackpack.client.luau @@ -0,0 +1,67 @@ +--!strict + +local Players = game:GetService("Players") + +local player = Players.LocalPlayer +local backpack = player:WaitForChild("Backpack") +local character = player.Character or player.CharacterAdded:Wait() + +-- Check if instance is an item +local function isItem(instance: Tool | HopperBin): boolean + return instance:IsA("Tool") or instance:IsA("HopperBin") +end + +-- Connect to item events +local function onItem(item: Tool | HopperBin) + if not isItem(item) then + return + end + + print("[Added]", item.Name) + + item.AncestryChanged:Connect(function(_, newParent) + if newParent == character then + print("[Equipped]", item.Name) + elseif newParent == backpack then + print("[Unequipped]", item.Name) + elseif newParent == nil then + print("[Removed]", item.Name) + end + end) +end + +local function onChildAdded(child) + if isItem(child) then + onItem(child) + end +end + +local function onChildRemoved(child) + if isItem(child) and child.Parent ~= character and child.Parent ~= backpack then + print("[Removed]", child.Name) + end +end + +backpack.ChildAdded:Connect(onChildAdded) +backpack.ChildRemoved:Connect(onChildRemoved) +character.ChildAdded:Connect(onChildAdded) +character.ChildRemoved:Connect(onChildRemoved) + +-- Handle character respawn +player.CharacterAdded:Connect(function(newCharacter) + character = newCharacter + character.ChildAdded:Connect(onChildAdded) + character.ChildRemoved:Connect(onChildRemoved) + + for _, child in character:GetChildren() do + onChildAdded(child) + end +end) + +-- Add existing items in backpack and character +for _, child in backpack:GetChildren() do + onChildAdded(child) +end +for _, child in character:GetChildren() do + onChildAdded(child) +end