From ad05bc1bb228bc9273ef31280c4cddae74d3ae7e Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 13 Feb 2026 22:01:30 +0000 Subject: [PATCH 001/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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/206] 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 From 0eea45b9c9afa07b00222bcdebfcffefa7e961c0 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 16 Apr 2026 01:57:13 -0700 Subject: [PATCH 187/206] Remove beginning newline Signed-off-by: Ryan Luu --- 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 - 18 files changed, 18 deletions(-) diff --git a/src/Components/App.story.luau b/src/Components/App.story.luau index a1c60ae0..1aaabecf 100644 --- a/src/Components/App.story.luau +++ b/src/Components/App.story.luau @@ -1,4 +1,3 @@ - const React = require("../../react") const App = require("./App") diff --git a/src/Components/Backpack.luau b/src/Components/Backpack.luau index 906328d6..6b2c770e 100644 --- a/src/Components/Backpack.luau +++ b/src/Components/Backpack.luau @@ -1,4 +1,3 @@ - const React = require("../../react") const Hotbar = require("./Hotbar") diff --git a/src/Components/Backpack.story.luau b/src/Components/Backpack.story.luau index 35934a65..4d37936a 100644 --- a/src/Components/Backpack.story.luau +++ b/src/Components/Backpack.story.luau @@ -1,4 +1,3 @@ - const React = require("../../react") const Backpack = require("./Backpack") diff --git a/src/Components/Hotbar.luau b/src/Components/Hotbar.luau index 779245a6..da9acf2c 100644 --- a/src/Components/Hotbar.luau +++ b/src/Components/Hotbar.luau @@ -1,4 +1,3 @@ - const React = require("../../react") const Slot = require("./Slot") diff --git a/src/Components/Hotbar.story.luau b/src/Components/Hotbar.story.luau index 018e50c0..27910a56 100644 --- a/src/Components/Hotbar.story.luau +++ b/src/Components/Hotbar.story.luau @@ -1,4 +1,3 @@ - const React = require("../../react") const Hotbar = require("./Hotbar") diff --git a/src/Components/HotbarHint.luau b/src/Components/HotbarHint.luau index 65ee1600..e3e82ae8 100644 --- a/src/Components/HotbarHint.luau +++ b/src/Components/HotbarHint.luau @@ -1,4 +1,3 @@ - const UserInputService = game:GetService("UserInputService") const React = require("../../react") diff --git a/src/Components/HotbarHint.story.luau b/src/Components/HotbarHint.story.luau index 829fa10a..9e49c66b 100644 --- a/src/Components/HotbarHint.story.luau +++ b/src/Components/HotbarHint.story.luau @@ -1,4 +1,3 @@ - const React = require("../../react") const HotbarHint = require("./HotbarHint") diff --git a/src/Components/Inventory.luau b/src/Components/Inventory.luau index aac090cf..3204590f 100644 --- a/src/Components/Inventory.luau +++ b/src/Components/Inventory.luau @@ -1,4 +1,3 @@ - const React = require("../../react") const Searchbar = require("./Searchbar") diff --git a/src/Components/Inventory.story.luau b/src/Components/Inventory.story.luau index f245e935..3757072b 100644 --- a/src/Components/Inventory.story.luau +++ b/src/Components/Inventory.story.luau @@ -1,4 +1,3 @@ - const React = require("../../react") const Inventory = require("./Inventory") diff --git a/src/Components/InventoryHint.luau b/src/Components/InventoryHint.luau index d50c6081..b729ba5c 100644 --- a/src/Components/InventoryHint.luau +++ b/src/Components/InventoryHint.luau @@ -1,4 +1,3 @@ - const UserInputService = game:GetService("UserInputService") const React = require("../../react") diff --git a/src/Components/InventoryHint.story.luau b/src/Components/InventoryHint.story.luau index 60ae6f41..215ffa3e 100644 --- a/src/Components/InventoryHint.story.luau +++ b/src/Components/InventoryHint.story.luau @@ -1,4 +1,3 @@ - const React = require("../../react") const InventoryHint = require("./InventoryHint") diff --git a/src/Components/Satchel.storybook.luau b/src/Components/Satchel.storybook.luau index 82e2fb30..eea63c37 100644 --- a/src/Components/Satchel.storybook.luau +++ b/src/Components/Satchel.storybook.luau @@ -1,4 +1,3 @@ - const React = require("../../react") const ReactRoblox = require("../../react-roblox") diff --git a/src/Components/Searchbar.luau b/src/Components/Searchbar.luau index 2bdc7968..172b3b75 100644 --- a/src/Components/Searchbar.luau +++ b/src/Components/Searchbar.luau @@ -1,4 +1,3 @@ - const React = require("../../react") export type Props = { diff --git a/src/Components/Searchbar.story.luau b/src/Components/Searchbar.story.luau index 8fdadd2f..5b7a2c8a 100644 --- a/src/Components/Searchbar.story.luau +++ b/src/Components/Searchbar.story.luau @@ -1,4 +1,3 @@ - const React = require("../../react") const Searchbar = require("./Searchbar") diff --git a/src/Components/Slot.luau b/src/Components/Slot.luau index 53d2d08b..3d01adff 100644 --- a/src/Components/Slot.luau +++ b/src/Components/Slot.luau @@ -1,4 +1,3 @@ - const React = require("../../react") const Tooltip = require("./Tooltip") diff --git a/src/Components/Slot.story.luau b/src/Components/Slot.story.luau index 287b526e..95962cec 100644 --- a/src/Components/Slot.story.luau +++ b/src/Components/Slot.story.luau @@ -1,4 +1,3 @@ - const React = require("../../react") const Slot = require("./Slot") diff --git a/src/Components/Tooltip.luau b/src/Components/Tooltip.luau index f43b65f6..9fa9d57f 100644 --- a/src/Components/Tooltip.luau +++ b/src/Components/Tooltip.luau @@ -1,4 +1,3 @@ - const React = require("../../react") export type Props = { diff --git a/src/Components/Tooltip.story.luau b/src/Components/Tooltip.story.luau index fb96a78c..caea0653 100644 --- a/src/Components/Tooltip.story.luau +++ b/src/Components/Tooltip.story.luau @@ -1,4 +1,3 @@ - const React = require("../../react") const Tooltip = require("./Tooltip") From c5d37f89178f90f2f54414bdc4ab9ed099aa4acb Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 16 Apr 2026 01:57:19 -0700 Subject: [PATCH 188/206] Add api const Signed-off-by: Ryan Luu --- src/init.luau | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/init.luau b/src/init.luau index 617d3161..8c623fdf 100644 --- a/src/init.luau +++ b/src/init.luau @@ -1,17 +1,18 @@ --!strict +const api = script.Api const bindableEvents = script.BindableEvents 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), - isInventoryOpen = require(script.Api.isInventoryOpen), + getEnabled = require(api.getEnabled), + setEnabled = require(api.setEnabled), + getTheme = require(api.getTheme), + setTheme = require(api.setTheme), + getTopbarIcon = require(api.getTopbarIcon), + openInventory = require(api.openInventory), + closeInventory = require(api.closeInventory), + isInventoryOpen = require(api.isInventoryOpen), -- Events backpackItemAdded = bindableEvents.BackpackItemAdded.Event, From fb941e716bf2e6c13045b54be25c776f90943bc5 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Thu, 16 Apr 2026 18:58:48 -0700 Subject: [PATCH 189/206] Simplify Rojo projects Signed-off-by: Ryan Luu --- develop.project.json | 13 ------------- test.project.json | 2 +- 2 files changed, 1 insertion(+), 14 deletions(-) delete mode 100644 develop.project.json diff --git a/develop.project.json b/develop.project.json deleted file mode 100644 index 6ca3f5a7..00000000 --- a/develop.project.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "Develop Satchel", - "emitLegacyScripts": false, - "tree": { - "$className": "DataModel", - "ReplicatedStorage": { - "$className": "ReplicatedStorage", - "Satchel": { - "$path": "models/Satchel" - } - } - } -} \ No newline at end of file diff --git a/test.project.json b/test.project.json index 98f301b8..bb738310 100644 --- a/test.project.json +++ b/test.project.json @@ -1,5 +1,5 @@ { - "name": "Test Satchel", + "name": "Satchel", "emitLegacyScripts": false, "tree": { "$className": "DataModel", From ad481530395c10c762369a407a050be30d5dbec6 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 18 Apr 2026 03:26:46 -0700 Subject: [PATCH 190/206] Fix hint scaling at smaller sizes Signed-off-by: Ryan Luu --- src/Components/App.luau | 1 + src/Design.rbxmx | 880 ++++++++++++++++++++-------------------- 2 files changed, 441 insertions(+), 440 deletions(-) diff --git a/src/Components/App.luau b/src/Components/App.luau index 39d1285f..624310a3 100644 --- a/src/Components/App.luau +++ b/src/Components/App.luau @@ -58,6 +58,7 @@ const function App(props: Props) [React.Tag] = "InventoryHints", }, { Hints = React.createElement("Frame", { + Size = UDim2.fromOffset(backpackSize.X, 0), Visible = props.opened, LayoutOrder = -1, [React.Tag] = "Hints", diff --git a/src/Design.rbxmx b/src/Design.rbxmx index 8660507d..848d34a6 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,64 +11,7 @@ -1 - - - AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= - 0 - false - DefaultTheme - -1 - - - - - 0 - RBX597525B19488436AA33F0688DED3EFBF - - 0 - false - Derive from BaseTokens - -1 - - - - - - - - 0 - false - LegacyTheme - -1 - - - - - 0 - RBX597525B19488436AA33F0688DED3EFBF - - 0 - false - Derive from BaseTokens - -1 - - - - - + 0 @@ -77,66 +20,103 @@ bmRDb2xvcg/NzMw+zczMPs3MzD4OAAAAVG9vbFRpcFBhZGRpbmcJAAAAAAIAAAA=]]>-1 - + 0 - + - .HotbarHint + .Inventory 0 false - .HotbarHint + .Inventory -1 - + 0 - + - >ImageLabel + ::UIPadding 0 false - >ImageLabel + ::UIPadding + -1 + + + + + + 0 + + + >ScrollingFrame + + 0 + false + >ScrollingFrame -1 - + 0 - AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== + - ::UIAspectRatioConstraint + ::UIListLayout 0 false - ::UIAspectRatioConstraint + ::UIListLayout -1 - + 0 - AQAAAAcAAABWaXNpYmxlAwE= + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz - @PreferredInputGamepad + ::UICorner 0 false - @PreferredInputGamepad + ::UICorner + -1 + + + + + + 0 + AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA + + ::UIListLayout + + 0 + false + ::UIListLayout -1 - + 0 -1 - + 0 - + 0 - + - TextBox.Searchbar + .HotbarHints 0 false - TextBox.Searchbar + .HotbarHints -1 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - - - 0 - - - ::UIStroke - - 0 - false - ::UIStroke - -1 - - - - - - 0 - - - ::UIPadding - - 0 - false - ::UIPadding - -1 - - - - - - 0 - + - >ImageButton + ::UIListLayout 0 false - >ImageButton + ::UIListLayout -1 - - - 0 - AAAAAA== - - ::UIAspectRatioConstraint - - 0 - false - ::UIAspectRatioConstraint - -1 - - - - + 0 - + - .Inventory + .HotbarHint 0 false - .Inventory + .HotbarHint -1 - + 0 - + - >ScrollingFrame + >ImageLabel 0 false - >ScrollingFrame + >ImageLabel -1 - + 0 - + AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== - ::UIListLayout + ::UIAspectRatioConstraint 0 false - ::UIListLayout + ::UIAspectRatioConstraint -1 - - - 0 - AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA - - ::UIListLayout - - 0 - false - ::UIListLayout - -1 - - - - - - 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - + 0 - + AQAAAAcAAABWaXNpYmxlAwE= - ::UIPadding + @PreferredInputGamepad 0 false - ::UIPadding + @PreferredInputGamepad -1 - + 0 - + - TextLabel.Tooltip + TextBox.Searchbar 0 false - TextLabel.Tooltip + TextBox.Searchbar -1 - + 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz + - ::UICorner + ::UIStroke 0 false - ::UICorner + ::UIStroke -1 - + 0 - + - ::UIPadding + >ImageButton 0 false - ::UIPadding + >ImageButton -1 + + + 0 + AAAAAA== + + ::UIAspectRatioConstraint + + 0 + false + ::UIAspectRatioConstraint + -1 + + + - - - - 0 - - - .Backpack - - 0 - false - .Backpack - -1 - - - + 0 - AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= + - ::UIListLayout + ::UIPadding 0 false - ::UIListLayout + ::UIPadding -1 - - - - 0 - RBX37676FEA32EC44EE85F071FAA3D8B38E - - 0 - false - Derive from DefaultTheme - -1 - - - - - - 0 - - - .HotbarHints - - 0 - false - .HotbarHints - -1 - - - + 0 - + AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= - ::UIListLayout + ::UICorner 0 false - ::UIListLayout + ::UICorner -1 - + 0 -1 - + 0 - + - >ImageLabel + ::UIPadding 0 false - >ImageLabel + ::UIPadding -1 - - - 0 - AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - + 0 - AAAAAA== + - .Equipped + >ImageLabel 0 false - .Equipped + >ImageLabel -1 - + 0 - + AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== - ::UIStroke + ::UICorner 0 false - ::UIStroke + ::UICorner -1 - - - 0 - - - ::UIPadding - - 0 - false - ::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 - AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz - - ::UICorner - - 0 - false - ::UICorner - -1 - - - - + 0 AgAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAAHAAAAVmlzaWJsZQMA @@ -636,7 +460,7 @@ YWRkaW5nVG9wAgwAAAAkU2xvdFBhZGRpbmc=]]> -1 - + 0 -1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -670,50 +494,95 @@ AAAAVGV4dFlBbGlnbm1lbnQVDgAAAFRleHRZQWxpZ25tZW50AAAAAAcAAABWaXNpYmxlAwA=]]> - + + + 0 + AQAAAAcAAABWaXNpYmxlAwA= + + .Tooltip + + 0 + false + .Tooltip + -1 + + + + + + + 0 + AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz + + ::UICorner + + 0 + false + ::UICorner + -1 + + + + + + 0 + AAAAAA== + + :Press + + 0 + false + :Press + -1 + + + 0 - AQAAAAcAAABWaXNpYmxlAwA= + AQAAAAcAAABWaXNpYmxlAwE= - .Tooltip + >.Tooltip 0 false - .Tooltip + >.Tooltip -1 - + 0 AAAAAA== - :Hover + .Equipped 0 false - :Hover + .Equipped -1 - + 0 - AQAAAAcAAABWaXNpYmxlAwE= + - >.Tooltip + ::UIStroke 0 false - >.Tooltip + ::UIStroke -1 - + 0 - + 0 - + AAAAAA== - .Unlocked + :Hover 0 false - .Unlocked + :Hover -1 - + 0 - AAAAAA== + AQAAAAcAAABWaXNpYmxlAwE= - :Press + >.Tooltip 0 false - :Press + >.Tooltip -1 - - - 0 - - - ::UIStroke - - 0 - false - ::UIStroke - -1 - - - - + 0 - + - .InventoryHints + .Hotbar 0 false - .InventoryHints + .Hotbar -1 - + 0 - AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= + ::UIListLayout @@ -802,41 +656,72 @@ dW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/]]> + + + 0 + AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= + + ::UIPadding + + 0 + false + ::UIPadding + -1 + + + - + 0 - + RBX702B341868524173BD2BB3E0FE5B87A1 + + 0 + false + Derive from DefaultTheme + -1 + + + + + + 0 + - .Hotbar + TextLabel.Tooltip 0 false - .Hotbar + TextLabel.Tooltip -1 - + 0 - + AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz - ::UIListLayout + ::UICorner 0 false - ::UIListLayout + ::UICorner -1 - + 0 - AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= + ::UIPadding @@ -848,7 +733,7 @@ aWdubWVudBURAAAAVmVydGljYWxBbGlnbm1lbnQAAAAA]]> - + 0 -1 - - - 0 - AQAAAAcAAABWaXNpYmxlAwE= - - @PreferredInputGamepad - - 0 - false - @PreferredInputGamepad - -1 - - - - + 0 - + 0 -1 - + 0 AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== @@ -925,8 +796,51 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAAAAACUAAAAAAAAAJQAAAA==]]> + + + 0 + AQAAAAcAAABWaXNpYmxlAwE= + + @PreferredInputGamepad + + 0 + false + @PreferredInputGamepad + -1 + + + + + + + 0 + + + .Backpack + + 0 + false + .Backpack + -1 + + + + + 0 + AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + - + 9 AQAAAAcAAABWaXNpYmxlAwE= @@ -940,8 +854,37 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAAAAACUAAAAAAAAAJQAAAA==]]> + + + 0 + + + .InventoryHints + + 0 + false + .InventoryHints + -1 + + + + + 0 + AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= + + ::UIListLayout + + 0 + false + ::UIListLayout + -1 + + + + - + -1 - + 0 - RBXB2E2303B06E24171A3A616F9D757C70D + RBX80D456B1BD1C4840A0DAFFE1910ABD7B 0 false @@ -995,7 +938,7 @@ VGV4dFNpemU=]]> - + + + + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= + 0 + false + DefaultTheme + -1 + + + + + 0 + RBXC34F5C112BB1449EBBBC755622074CF3 + + 0 + false + Derive from BaseTokens + -1 + + + + + + + + 0 + false + LegacyTheme + -1 + + + + + 0 + RBXC34F5C112BB1449EBBBC755622074CF3 + + 0 + false + Derive from BaseTokens + -1 + + + + \ No newline at end of file From 38c0b721ddf1c8c1a77b83167250b87546860ad2 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 18 Apr 2026 03:51:22 -0700 Subject: [PATCH 191/206] Remove top level visible tag Signed-off-by: Ryan Luu --- src/Design.rbxmx | 178 +++++++++++++++++++++++++---------------------- 1 file changed, 96 insertions(+), 82 deletions(-) diff --git a/src/Design.rbxmx b/src/Design.rbxmx index 848d34a6..e76baa0d 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,7 +11,7 @@ -1 - + 0 @@ -20,7 +20,7 @@ -1 - + 0 -1 - + 0 - + 0 -1 - + 0 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz @@ -101,7 +101,7 @@ CQAAAAAFAAAACQAAAFNvcnRPcmRlchUJAAAAU29ydE9yZGVyAgAAAAUAAABXcmFwcwMB]]> - + 0 AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA @@ -116,7 +116,7 @@ CQAAAAAFAAAACQAAAFNvcnRPcmRlchUJAAAAU29ydE9yZGVyAgAAAAUAAABXcmFwcwMB]]> - + 0 -1 - + 0 - + 0 -1 - + 0 - + 0 -1 - + 0 -1 - + 0 AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== @@ -224,7 +224,7 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAA==]]> - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -238,8 +238,22 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAA==]]> + + + 0 + AQAAAAcAAABWaXNpYmxlAwE= + + .Visible + + 0 + false + .Visible + -1 + + + - + 0 -1 - + 0 - + 0 -1 - + 0 AAAAAA== @@ -307,7 +321,7 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAA==]]> - + 0 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= @@ -338,7 +352,7 @@ ZwoAAABQYWRkaW5nVG9wAg4AAAAkU2VhcmNoUGFkZGluZw==]]> - + 0 -1 - + 0 - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== @@ -402,7 +416,7 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> - + 0 -1 - + 0 AAAAAA== @@ -429,7 +443,7 @@ chYAAABCYWNrZ3JvdW5kVHJhbnNwYXJlbmN5BgAAAAAAAAAA]]> -1 - + 0 - + 0 AgAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAAHAAAAVmlzaWJsZQMA @@ -460,7 +474,7 @@ cgIVAAAAJFNsb3RQcmVzc1N0cm9rZUNvbG9yCQAAAFRoaWNrbmVzcwYAAAAAAAAAQA==]]>-1 - + 0 -1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -494,7 +508,7 @@ AAAAVGV4dFlBbGlnbm1lbnQVDgAAAFRleHRZQWxpZ25tZW50AAAAAAcAAABWaXNpYmxlAwA=]]> - + 0 AQAAAAcAAABWaXNpYmxlAwA= @@ -509,7 +523,7 @@ AAAAVGV4dFlBbGlnbm1lbnQVDgAAAFRleHRZQWxpZ25tZW50AAAAAAcAAABWaXNpYmxlAwA=]]> - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz @@ -523,7 +537,7 @@ AAAAVGV4dFlBbGlnbm1lbnQVDgAAAFRleHRZQWxpZ25tZW50AAAAAAcAAABWaXNpYmxlAwA=]]> - + 0 AAAAAA== @@ -536,7 +550,7 @@ AAAAVGV4dFlBbGlnbm1lbnQVDgAAAFRleHRZQWxpZ25tZW50AAAAAAcAAABWaXNpYmxlAwA=]]>-1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -551,7 +565,7 @@ AAAAVGV4dFlBbGlnbm1lbnQVDgAAAFRleHRZQWxpZ25tZW50AAAAAAcAAABWaXNpYmxlAwA=]]> - + 0 AAAAAA== @@ -564,7 +578,7 @@ AAAAVGV4dFlBbGlnbm1lbnQVDgAAAFRleHRZQWxpZ25tZW50AAAAAAcAAABWaXNpYmxlAwA=]]>-1 - + 0 - + 0 - + 0 AAAAAA== @@ -610,7 +624,7 @@ AAAAAAAoQA==]]> -1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -626,7 +640,7 @@ AAAAAAAoQA==]]> - + 0 -1 - + 0 - + 0 AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= @@ -671,10 +685,10 @@ aWdubWVudBURAAAAVmVydGljYWxBbGlnbm1lbnQAAAAA]]> - + 0 - RBX702B341868524173BD2BB3E0FE5B87A1 + RBX3C1DA478165B4DC18B938ACA5E9F2F71 0 false @@ -683,7 +697,7 @@ aWdubWVudBURAAAAVmVydGljYWxBbGlnbm1lbnQAAAAA]]> - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz @@ -716,7 +730,7 @@ ZXh0U2l6ZQ==]]> - + 0 - + 0 -1 - + 0 - + 0 -1 - + 0 AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== @@ -796,7 +810,7 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAAAAACUAAAAAAAAAJQAAAA==]]> - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -810,8 +824,22 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAAAAACUAAAAAAAAAJQAAAA==]]> + + + 0 + AQAAAAcAAABWaXNpYmxlAwE= + + .Visible + + 0 + false + .Visible + -1 + + + - + 0 -1 - + 0 AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= @@ -840,21 +868,7 @@ ABYAAABCYWNrZ3JvdW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/]]> - - - 9 - AQAAAAcAAABWaXNpYmxlAwE= - - .Visible - - 0 - false - .Visible - -1 - - - - + 0 -1 - + 0 AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= @@ -884,7 +898,7 @@ dW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/]]> - + -1 - + 0 - RBX80D456B1BD1C4840A0DAFFE1910ABD7B + RBX0CA618DF96E24F81AA36495453EC15D3 0 false @@ -938,7 +952,7 @@ VGV4dFNpemU=]]> - + - + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= 0 @@ -963,10 +977,10 @@ Pw==]]> -1 - + 0 - RBXC34F5C112BB1449EBBBC755622074CF3 + RBX7B0DBBC4BF79418B878FBAEE0A994375 0 false @@ -976,7 +990,7 @@ Pw==]]> - + -1 - + 0 - RBXC34F5C112BB1449EBBBC755622074CF3 + RBX7B0DBBC4BF79418B878FBAEE0A994375 0 false From 87128a396ee0b19cdb878d37dcea6ec0a2e58197 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Mon, 20 Apr 2026 23:44:39 -0700 Subject: [PATCH 192/206] Combine visible tag Signed-off-by: Ryan Luu --- src/Design.rbxmx | 172 ++++++++++++++++++++--------------------------- 1 file changed, 72 insertions(+), 100 deletions(-) diff --git a/src/Design.rbxmx b/src/Design.rbxmx index e76baa0d..1bdd9ba6 100644 --- a/src/Design.rbxmx +++ b/src/Design.rbxmx @@ -2,7 +2,7 @@ true null nil - + 0 @@ -11,7 +11,7 @@ -1 - + 0 @@ -20,7 +20,7 @@ -1 - + 0 -1 - + 0 - + 0 -1 - + 0 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRTdXJmYWNlQ29ybmVyUmFkaXVz @@ -101,7 +101,7 @@ CQAAAAAFAAAACQAAAFNvcnRPcmRlchUJAAAAU29ydE9yZGVyAgAAAAUAAABXcmFwcwMB]]> - + 0 AQAAAAcAAABQYWRkaW5nCQAAAAAFAAAA @@ -116,7 +116,7 @@ CQAAAAAFAAAACQAAAFNvcnRPcmRlchUJAAAAU29ydE9yZGVyAgAAAAUAAABXcmFwcwMB]]> - + 0 -1 - + 0 - + 0 -1 - + 0 - + 0 -1 - + 0 -1 - + 0 AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAAAQA== @@ -224,36 +224,22 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAA==]]> - + 0 AQAAAAcAAABWaXNpYmxlAwE= - @PreferredInputGamepad + @PreferredInputGamepad,.Visible 0 false - @PreferredInputGamepad - -1 - - - - - - 0 - AQAAAAcAAABWaXNpYmxlAwE= - - .Visible - - 0 - false - .Visible + @PreferredInputGamepad,.Visible -1 - + 0 -1 - + 0 - + 0 -1 - + 0 AAAAAA== @@ -321,7 +307,7 @@ BAAAAFNpemUKAACAPwAAAAAAAIA/AAAAAA==]]> - + 0 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFgAAACRDb250YWluZXJDb3JuZXJSYWRpdXM= @@ -352,7 +338,7 @@ ZwoAAABQYWRkaW5nVG9wAg4AAAAkU2VhcmNoUGFkZGluZw==]]> - + 0 -1 - + 0 - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFQAAACRTbG90SWNvbkNvcm5lclJhZGl1cw== @@ -416,7 +402,7 @@ AAAAU2l6ZQoAAIA/AAAAAAAAgD8AAAAA]]> - + 0 -1 - + 0 AAAAAA== @@ -443,7 +429,7 @@ chYAAABCYWNrZ3JvdW5kVHJhbnNwYXJlbmN5BgAAAAAAAAAA]]> -1 - + 0 - + 0 AgAAAAQAAABTaXplCgAAAAAAAAAAAAAAAAAAAAAHAAAAVmlzaWJsZQMA @@ -474,7 +460,7 @@ cgIVAAAAJFNsb3RQcmVzc1N0cm9rZUNvbG9yCQAAAFRoaWNrbmVzcwYAAAAAAAAAQA==]]>-1 - + 0 -1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -508,7 +494,7 @@ AAAAVGV4dFlBbGlnbm1lbnQVDgAAAFRleHRZQWxpZ25tZW50AAAAAAcAAABWaXNpYmxlAwA=]]> - + 0 AQAAAAcAAABWaXNpYmxlAwA= @@ -523,7 +509,7 @@ AAAAVGV4dFlBbGlnbm1lbnQVDgAAAFRleHRZQWxpZ25tZW50AAAAAAcAAABWaXNpYmxlAwA=]]> - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCEQAAACRTbG90Q29ybmVyUmFkaXVz @@ -537,7 +523,7 @@ AAAAVGV4dFlBbGlnbm1lbnQVDgAAAFRleHRZQWxpZ25tZW50AAAAAAcAAABWaXNpYmxlAwA=]]> - + 0 AAAAAA== @@ -550,7 +536,7 @@ AAAAVGV4dFlBbGlnbm1lbnQVDgAAAFRleHRZQWxpZ25tZW50AAAAAAcAAABWaXNpYmxlAwA=]]>-1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -565,7 +551,7 @@ AAAAVGV4dFlBbGlnbm1lbnQVDgAAAFRleHRZQWxpZ25tZW50AAAAAAcAAABWaXNpYmxlAwA=]]> - + 0 AAAAAA== @@ -578,7 +564,7 @@ AAAAVGV4dFlBbGlnbm1lbnQVDgAAAFRleHRZQWxpZ25tZW50AAAAAAcAAABWaXNpYmxlAwA=]]>-1 - + 0 - + 0 - + 0 AAAAAA== @@ -624,7 +610,7 @@ AAAAAAAoQA==]]> -1 - + 0 AQAAAAcAAABWaXNpYmxlAwE= @@ -640,7 +626,7 @@ AAAAAAAoQA==]]> - + 0 -1 - + 0 - + 0 AgAAAAsAAABQYWRkaW5nTGVmdAkAAAAABQAAAAwAAABQYWRkaW5nUmlnaHQJAAAAAAUAAAA= @@ -685,10 +671,10 @@ aWdubWVudBURAAAAVmVydGljYWxBbGlnbm1lbnQAAAAA]]> - + 0 - RBX3C1DA478165B4DC18B938ACA5E9F2F71 + RBX4FFE90AE43704D19A9B55E33BC2823A0 0 false @@ -697,7 +683,7 @@ aWdubWVudBURAAAAVmVydGljYWxBbGlnbm1lbnQAAAAA]]> - + 0 -1 - + 0 AQAAAAwAAABDb3JuZXJSYWRpdXMCFAAAACRUb29sVGlwQ29ybmVyUmFkaXVz @@ -730,7 +716,7 @@ ZXh0U2l6ZQ==]]> - + 0 - + 0 -1 - + 0 - + 0 -1 - + 0 AQAAAAsAAABBc3BlY3RSYXRpbwYAAAAAAAD4Pw== @@ -810,36 +796,22 @@ AABTY2FsZVR5cGUDAAAABAAAAFNpemUKAAAAACUAAAAAAAAAJQAAAA==]]> - - - 0 - AQAAAAcAAABWaXNpYmxlAwE= - - @PreferredInputGamepad - - 0 - false - @PreferredInputGamepad - -1 - - - - + 0 AQAAAAcAAABWaXNpYmxlAwE= - .Visible + @PreferredInputGamepad,.Visible 0 false - .Visible + @PreferredInputGamepad,.Visible -1 - + 0 -1 - + 0 AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= @@ -868,7 +840,7 @@ ABYAAABCYWNrZ3JvdW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/]]> - + 0 -1 - + 0 AQAAAAkAAABTb3J0T3JkZXIVCQAAAFNvcnRPcmRlcgIAAAA= @@ -898,7 +870,7 @@ dW5kVHJhbnNwYXJlbmN5BgAAAAAAAPA/]]> - + -1 - + 0 - RBX0CA618DF96E24F81AA36495453EC15D3 + RBX45EBE9EB3D7C433CA888B0E29B9FC464 0 false @@ -952,7 +924,7 @@ VGV4dFNpemU=]]> - + - + AQAAAA0AAABTdHlsZUNhdGVnb3J5AgYAAABUaGVtZXM= 0 @@ -977,10 +949,10 @@ Pw==]]> -1 - + 0 - RBX7B0DBBC4BF79418B878FBAEE0A994375 + RBXA96A2BC50C474CD9929B9019E117AD67 0 false @@ -990,7 +962,7 @@ Pw==]]> - + -1 - + 0 - RBX7B0DBBC4BF79418B878FBAEE0A994375 + RBXA96A2BC50C474CD9929B9019E117AD67 0 false From 28df325488ae4ea62b2e8bbe3b3b1304d5d243ac Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Tue, 21 Apr 2026 02:49:46 -0700 Subject: [PATCH 193/206] Add wally.lock syntax highlighting Signed-off-by: Ryan Luu --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index 86670b24..873a5d37 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ *.rbxmx linguist-language=XML +wally.lock linguist-language=TOML From 7c43f2471d0e1f207bf31b4d4ae6c97ffdc865d1 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 24 Apr 2026 02:13:29 +0000 Subject: [PATCH 194/206] Bump docs version Signed-off-by: GitHub --- .github/workflows/docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 52439489..d6b65295 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -14,7 +14,7 @@ permissions: contents: write env: - VERSION: 1.x + VERSION: 2.x jobs: deploy: From eed12bcab0e13887844b8bcff9baafa77fa91914 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 24 Apr 2026 02:14:35 +0000 Subject: [PATCH 195/206] Update branding Signed-off-by: GitHub --- docs/assets/favicon.svg | 6 +++--- docs/assets/logo.svg | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/assets/favicon.svg b/docs/assets/favicon.svg index 41701e53..562663dc 100644 --- a/docs/assets/favicon.svg +++ b/docs/assets/favicon.svg @@ -1,4 +1,4 @@ - - - + + + \ No newline at end of file diff --git a/docs/assets/logo.svg b/docs/assets/logo.svg index 4d8c7e6c..3ea8838b 100644 --- a/docs/assets/logo.svg +++ b/docs/assets/logo.svg @@ -1,3 +1,3 @@ - + \ No newline at end of file From bf8fe40a134864fb17fdf164020b6b58ffee2527 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 24 Apr 2026 02:18:29 +0000 Subject: [PATCH 196/206] Fix missing mask for rounding corners Signed-off-by: GitHub --- docs/assets/logo.svg | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/assets/logo.svg b/docs/assets/logo.svg index 3ea8838b..bfca017d 100644 --- a/docs/assets/logo.svg +++ b/docs/assets/logo.svg @@ -1,3 +1,10 @@ - - \ No newline at end of file + + + + + + + + + From 0d0eea3769cc45169535ad4809cdc9fd451fc500 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 24 Apr 2026 02:28:43 +0000 Subject: [PATCH 197/206] Add basic API docs Signed-off-by: GitHub --- docs/api-reference.md | 249 +++++------------------------------------- 1 file changed, 29 insertions(+), 220 deletions(-) diff --git a/docs/api-reference.md b/docs/api-reference.md index af4f8f59..7bc26885 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -1,240 +1,49 @@ - - -Satchel is a reskin of the default BackpackGui located in [CoreGui]. Satchel acts very similar to the default backpack and is based on a fork on the default backpack. Behaviors between the two should remain the same with both of them managing the [Backpack]. - - [CoreGui]: https://create.roblox.com/docs/reference/engine/classes/CoreGui - [Backpack]: https://create.roblox.com/docs/reference/engine/classes/Backpack - -## Summary - -### Attributes - -| Attribute | Description | Default | -| :--- | :--- | :--- | -| BackgroundColor3: [`Color3`](https://create.roblox.com/docs/reference/engine/datatypes/Color3) | Determines the background color of the default inventory window and slots. | `[25, 27, 29]` | -| BackgroundTransparency: [`number`](https://create.roblox.com/docs/scripting/luau/numbers) | Determines the background transparency of the default inventory window and slots. | 0.3 | -| CornerRadius: [`UDim`](https://create.roblox.com/docs/reference/engine/datatypes/UDim) | Determines the radius, in pixels, of the default inventory window and slots. | `0, 8` | -| EquipBorderColor3: [`Color3`](https://create.roblox.com/docs/reference/engine/datatypes/Color3) | Determines the color of the equip border when a slot is equipped. | `[255, 255, 255]` | -| EquipBorderSizePixel: [`number`](https://create.roblox.com/docs/scripting/luau/numbers) | Determines the pixel width of the equip border when a slot is equipped. | `5` | -| FontFace: [`Font`](https://create.roblox.com/docs/reference/engine/enums/Font) | Determines the font of the default inventory window and slots. | `Builder Sans` | -| InsetIconPadding: [`boolean`](https://create.roblox.com/docs/scripting/luau/booleans) | Determines whether or not the tool icon is padded in the default inventory window and slots. | True | -| OutlineEquipBorder: [`boolean`](https://create.roblox.com/docs/scripting/luau/booleans) | Determines whether or not the equip border is outline or inset when a slot is equipped. | True | -| TextColor3: [`Color3`](https://create.roblox.com/docs/reference/engine/datatypes/Color3) | Determines the color of the text in default inventory window and slots. | `[255, 255, 255]` | -| TextSize: [`number`](https://create.roblox.com/docs/scripting/luau/numbers) | Determines the size of the text in the default inventory window and slots. | `14` | -| TextStrokeColor3: [`Color3`](https://create.roblox.com/docs/reference/engine/datatypes/Color3) | Determines the color of the text stroke of text in default inventory window and slots. | `[0, 0, 0]` | -| TextStrokeTransparency: [`number`](https://create.roblox.com/docs/scripting/luau/numbers) | Determines the transparency of the text stroke of text in default chat window and slots. | 0.5 | - -### Methods - -| IsOpened(): [`boolean`](https://create.roblox.com/docs/scripting/luau/booleans) | -| :--- | -| Returns whether the inventory is opened or not. | - -| SetBackpackEnabled(enabled: boolean): `void` | -| :--- | -| Sets whether the backpack gui is enabled or disabled. | - -| GetBackpackEnabled(): [`boolean`](https://create.roblox.com/docs/scripting/luau/booleans) | -| :--- | -| Returns whether the backpack gui is enabled or disabled. | - -| GetStateChangedEvent(): [`RBXScriptSignal`](https://create.roblox.com/docs/reference/engine/datatypes/RBXScriptSignal) | -| :--- | -| Returns a signal that fires when the inventory is opened or closed. | - -## Attributes - -### BackgroundColor3 - -[`Color3`](https://create.roblox.com/docs/reference/engine/datatypes/Color3) - -Determines the background color of the default inventory window and slots. Changing this will update the background color for all elements excluding the search box background for visibility purposes. - -### BackgroundTransparency - -[`number`](https://create.roblox.com/docs/luau/numbers) - -Determines the background transparency of the default inventory window and slots. This will change how the hot bar looks in its locked state and the inventory background. - -### CornerRadius - -[`UDim`](https://create.roblox.com/docs/reference/engine/datatypes/UDim) - -Determines the radius, in pixels, of the default inventory window and slots. This will affect all elements with a visible rounded corner. The corner radius for the search bar is calculated automatically based on this value. - -### EquipBorderColor3 - -[`Color3`](https://create.roblox.com/docs/reference/engine/datatypes/Color3) - -Determines the color of the equip border when a slot is equipped. The drag outline color of the slot will not changed by this. - -### EquipBorderSizePixel - -[`number`](https://create.roblox.com/docs/luau/numbers) - -Determines the pixel width of the equip border when a slot is equipped. This additionally controls the padding of tool icons. - -### FontFace - -[`Enum.Font`](https://create.roblox.com/docs/reference/engine/enums/Font) - -Determines the font of the default inventory window and slots. This includes all text in the Satchel UI. - -!!! bug - - Rojo does not support the [Font](https://create.roblox.com/docs/reference/engine/datatypes/Font) instance attribute so the it will not be synced. You may add the attribute manually if you wish to adjust the font. - -### InsetIconPadding - -[`bool`](https://create.roblox.com/docs/luau/booleans) - -Determines whether or not the tool icon is padded in the default inventory window and slots. Changing this will change how the tool icon is padded in the slot or not. - -### OutlineEquipBorder - -[`bool`](https://create.roblox.com/docs/luau/booleans) - -Determines whether or not the equip border is outline or inset when a slot is equipped. Changing this will make the equip border either border will outline or inset the slot. - -### TextColor3 - -[`Color3`](https://create.roblox.com/docs/reference/engine/datatypes/Color3) - -Determines the color of the text in default inventory window and slots. This will change the color of all text. - -### TextSize - -[`number`](https://create.roblox.com/docs/luau/numbers) - -Determines the size of the text in the default inventory window and slots. This will change the text size of the tool names and will not change other text like search text, hotkey number, and gamepad hints. - -### TextStrokeColor3 - -[`Color3`](https://create.roblox.com/docs/reference/engine/datatypes/Color3) - -Determines the color of the text stroke of text in default inventory window and slots. This will change the color of all text strokes which are visible. - -### TextStrokeTransparency - -[`number`](https://create.roblox.com/docs/luau/numbers) - -Determines the transparency of the text stroke of text in default chat window and slots. This will change all text strokes in which text strokes are visible. - ## Methods -### IsOpened +### getEnabled -Returns whether the inventory is opened or not. - -#### Returns - - - - - -
bool
- -### SetBackpackEnabled - -Sets whether the backpack gui is enabled or disabled. - -#### Code Samples - -This code sample will disable the backpack gui. - -``` lua title="Disable Backpack" -local ReplicatedStorage = game:GetService("ReplicatedStorage") - -local Satchel = require(ReplicatedStorage.Satchel) - -Satchel.SetBackpackEnabled(false) +``` +getEnabled(): boolean ``` -#### Parameters - - - - - - -
enabled: boolWhether to enable or disable the Backpack
- -#### Returns - - - - - -
void
- -### GetBackpackEnabled - -Returns whether the backpack gui is enabled or disabled. - -#### Code Samples - -This code sample makes a TextButton that toggles the inventory when clicked. +### setEnabled -``` lua title="Toggle Satchel" -local ReplicatedStorage = game:GetService("ReplicatedStorage") +``` +setEnabled(enabled: boolean): () +``` -local Satchel = require(ReplicatedStorage.Satchel) +### getTheme -local button = Instance.new("TextButton") -button.AnchorPoint = Vector2.new(0.5, 0.5) -button.Position = UDim2.new(0.5, 0, 0.5, 0) -button.Text = "Toggle Inventory" -button.MouseButton1Click:Connect(function() - if Satchel:GetBackpackEnabled() then - Satchel.SetBackpackEnabled(false) - else - Satchel.SetBackpackEnabled(true) - end -end) +``` +getTheme(): StyleSheet ``` -#### Returns - - - - - -
bool
+### setTheme -### GetStateChangedEvent +``` +setTheme(theme: "DefaultTheme" | "LegacyTheme" | StyleSheet): () +``` -Returns a signal that fires when the inventory is opened or closed. +### getTopbarIcon -#### Code Samples +``` +getTopbarIcon(): TopbarPlus.Icon +``` -This code sample detects when the inventory is opened or closed. +### openInventory -``` lua title="Detect Inventory State" -local ReplicatedStorage = game:GetService("ReplicatedStorage") +``` +openInventory(): () +``` -local Satchel = require(ReplicatedStorage.Satchel) +### closeInventory -Satchel.GetStateChangedEvent():Connect(function(isOpened: boolean) - if isOpened then - print("Inventory opened") - else - print("Inventory closed") - end -end) +``` +closeInventory(): () ``` -#### Returns +### isInventoryOpen - - - - -
RBXScriptSignal
+``` +isInventoryOpen(): boolean +``` From 1adaccafd9e93f70edb89421bbcd25068ada6403 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 24 Apr 2026 02:28:56 +0000 Subject: [PATCH 198/206] Fix missing return type Signed-off-by: GitHub --- src/Api/setTheme.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Api/setTheme.luau b/src/Api/setTheme.luau index 36a11dc5..7aaf7133 100644 --- a/src/Api/setTheme.luau +++ b/src/Api/setTheme.luau @@ -8,7 +8,7 @@ const currentTheme = styleSheets.SatchelStyleSheet:FindFirstChildOfClass("StyleD type DefaultThemes = "DefaultTheme" | "LegacyTheme" -const function setTheme(theme: DefaultThemes | StyleSheet) +const function setTheme(theme: DefaultThemes | StyleSheet): () assert(RunService:IsClient(), "setTheme can only be called on the client") const newTheme: StyleSheet = if typeof(theme) == "string" then styleSheets:WaitForChild(theme) :: StyleSheet else theme From 26acb7f7c1c8fe23a1a1020076c8834f5989aba3 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 24 Apr 2026 02:30:07 +0000 Subject: [PATCH 199/206] Use minimal docs Signed-off-by: GitHub --- docs/alternatives.md | 55 -------------------------------------------- docs/introduction.md | 25 -------------------- docs/platforms.md | 52 ----------------------------------------- docs/usage.md | 49 --------------------------------------- mkdocs.yml | 4 ---- 5 files changed, 185 deletions(-) delete mode 100644 docs/alternatives.md delete mode 100644 docs/introduction.md delete mode 100644 docs/platforms.md delete mode 100644 docs/usage.md diff --git a/docs/alternatives.md b/docs/alternatives.md deleted file mode 100644 index b74831cd..00000000 --- a/docs/alternatives.md +++ /dev/null @@ -1,55 +0,0 @@ -Satchel isn't the best backpack system out there or the only one but it does offer some advantages against others. - -## Purse - -[Purse] is a sub project of Satchel and a fork on the CoreGui backpack. It tries to be as close as possible to the default backpack while Satchel tries to be an improvement over it. - - [Purse]: https://purse.luau.page/ - -### Pros - -- Easy to install, drag and drop installation -- Well documented -- Full platform support - -### Cons - -- Requires scripting knowledge to customize -- No new features over default backpack - -## NeoHotbar - -[Neobar] is a modern hotbar-only system that acts as a great alternative to Satchel if you are looking for a hotbar only. Made on a strong foundation and well-built, [Neobar] is a powerful tool with unparalleled customization and API. - - [Neobar]: https://loneka.com/neohotbar/ - -### Pros - -- Easy to install, drag and drop installation -- Powerful and highly customizable interface -- Well documented -- Full platform support - -### Cons - -- Requires scripting knowledge to customize -- No instance attributes -- Hotbar system only - -## ReInvent - -[ReInvent] is an older-style hotbar and inventory system that is made completely separate from the backpack core scripts. [ReInvent] is no longer supported and lacks proper documentation and developer-facing APIs. - - [ReInvent]: https://devforum.roblox.com/t/1822656 - -### Pros - -- Easy to install, drag and drop installation -- Animated interface -- Backpack and hotbar system - -### Cons - -- Computer and mobile platforms only -- Poor documentation -- Discontinued diff --git a/docs/introduction.md b/docs/introduction.md deleted file mode 100644 index ce5dfd1e..00000000 --- a/docs/introduction.md +++ /dev/null @@ -1,25 +0,0 @@ -Welcome to Satchel, a modern alternative to Roblox's default backpack. - -Satchel and its documentation are always a work in progress, but you can help too. See the [contributing guidelines](https://github.com/ryanlua/satchel/blob/main/.github/CONTRIBUTING.md) to find how you can improve Satchel. - -Just want to use Satchel? Check out [Installation]. - - [Installation]: installation.md - -## Improvements - -* Modernized and refreshed UI -* Customization using instance attributes -* Methods and events, previously locked to CoreGui -* Script readability and type improvements -* Rojo sync and Wally support - -All open source and free for you to use in your own Roblox experiences. - -## Satchel over Default - -While the default backpack does its job, customizing the UI or editing the script is extremely difficult. Did you know that the backpack they are using today is from 2015? (With lots of bandaids and patches of course.) Satchel acts as a modernized version that aims to be much more friendly while still maintaining as many features and compatibility. - -## CoreGui Relation - -From a scripting perspective, Satchel is more of an advanced fork of the CoreGui with Satchel borrowing a majority of its codebase from the default. It's not entirely copy and paste job though. Type annotations and performance optimizations set Satchel apart along with its number of UI tweaks and refactors in place. diff --git a/docs/platforms.md b/docs/platforms.md deleted file mode 100644 index ad5fc599..00000000 --- a/docs/platforms.md +++ /dev/null @@ -1,52 +0,0 @@ -We support all platforms that Roblox supports. Computers, phones, tablets, consoles, and VR are all supported by Satchel right out of the box. Where the default backpack should run, so should Satchel. - -!!! note - - Do you see a bug specific to a platform? [Open a bug report] we'll look into it. - - [Open a bug report]: https://github.com/ryanlua/satchel/issues/new - -## Current supported devices - -All platforms on Roblox are supported by Satchel, limited only by screen size. Below is a list of devices along with the accompanying interface and minimum screen size. - -### Computer - -Support for all computers with 1024 x 768px or larger. - -* 1024 x 768px minimum display size -* Desktop interface -* 10 hotbar slots - -### Phone - -Support for Apple iPhone 5 (568 x 320px) or newer. - -* 568 x 320px minimum display size -* Mobile interface -* 6 hotbar slots - -### Tablet - -Support for Apple iPad 2 (1024 x 768px) or newer. - -* 1024 x 768px minimum display size -* Mobile interface -* 10 or 6 hotbar slots (Depending on display size) - -### Console - -Support for Xbox and PlayStation. Specialized ten-foot interface and hint UI for controllers. Hint UI will automatically adapt to the correct controller buttons. - -* Ten-foot interface -* Controller context hint UI -* 10 hotbar slots - -### VR - -VR including Valve Index, Meta Quest 2 and above, and similar. - -* Adapted mobile interface -* Controller context hint UI -* Custom VR inventory controls -* 6 hotbar slots diff --git a/docs/usage.md b/docs/usage.md deleted file mode 100644 index 5ab91b72..00000000 --- a/docs/usage.md +++ /dev/null @@ -1,49 +0,0 @@ -Use of Satchel after installation very easy. Just [publish your experience to Roblox] and see Satchel live in action. - -To learn how to install Satchel, see [Installation]. - -!!! note - - Please see [API Reference] for more details on attributes, methods, and events for Satchel and how to use Satchel to it's full potential. - - [publish your experience to Roblox]: https://create.roblox.com/docs/production/publishing - [Installation]: installation.md - [API Reference]: api-reference.md - -### Customization - -Satchel is highly customizable & adjustable with [instance attributes] support allowing you to customize the behavior and appearance of over 10+ attributes. - -Some of the attributes include: - -* Text Color, Size, Stroke Color & Transparency -* Background Color & Transparency -* Equip Border Color & Thickness -* Corner Radius -* Font - -More attributes can be found in the [API Reference]. The list above is not exhaustive and there are may more attributes available for customization. - - [instance attributes]: https://create.roblox.com/docs/studio/instance-attributes - -
- ![Instance Attributes](assets/attributes-example.png) -
Example of customization using instance attributes
-
- -### Scripting - -Satchel offers methods and events for scripting purposes. In the below code example we will use the `SetBackpackEnabled` method to disable the Satchel. The script expects the Satchel module to be in [`ReplicatedStorage`][ReplicatedStorage]. - -``` lua title="Disable Backpack" -local ReplicatedStorage = game:GetService("ReplicatedStorage") - -local Satchel = require(ReplicatedStorage.Satchel) - -Satchel.SetBackpackEnabled(false) -``` - -For the full API reference, see [API Reference] for more details on attributes, methods, and events for Satchel and how to use Satchel to it's full potential. - - [ReplicatedStorage]: https://create.roblox.com/docs/reference/engine/classes/ReplicatedStorage - [SetBackpackEnabled]: api-reference.md#setbackpackenabled diff --git a/mkdocs.yml b/mkdocs.yml index 2ceb0d83..d061a2c8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -69,9 +69,5 @@ markdown_extensions: nav: - Home: index.md - - Introduction: introduction.md - Installation: installation.md - - Usage: usage.md - - Platforms: platforms.md - - Alternatives: alternatives.md - API Reference: api-reference.md From 82370890a6e753cefefd8a94386a65bd110cd77c Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 24 Apr 2026 02:31:05 +0000 Subject: [PATCH 200/206] Remove banner Signed-off-by: GitHub --- docs/overrides/main.html | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 docs/overrides/main.html diff --git a/docs/overrides/main.html b/docs/overrides/main.html deleted file mode 100644 index 243a9659..00000000 --- a/docs/overrides/main.html +++ /dev/null @@ -1,5 +0,0 @@ -{% extends "base.html" %} - -{% block announce %} - Satchel v1 is unmaintained to focus on v2 development. For a maintained alternative, see Purse. -{% endblock %} \ No newline at end of file From 510b4bb6cccb6c07d4e2cc740058b914359e4e33 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 24 Apr 2026 02:43:13 +0000 Subject: [PATCH 201/206] Remove override Signed-off-by: GitHub --- mkdocs.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index d061a2c8..073a9556 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -32,7 +32,6 @@ theme: repo: fontawesome/brands/github favicon: assets/favicon.svg logo: assets/logo.svg - custom_dir: docs/overrides extra: version: From 3f113340e70493a93006f90d349daca9cf185b0f Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 24 Apr 2026 02:44:08 +0000 Subject: [PATCH 202/206] Add descriptions Signed-off-by: GitHub --- docs/api-reference.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/api-reference.md b/docs/api-reference.md index 7bc26885..5785931e 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -6,44 +6,60 @@ getEnabled(): boolean ``` +Gets if the backpack is enabled. + ### setEnabled ``` setEnabled(enabled: boolean): () ``` +Sets whether the backpack is enabled or not. + ### getTheme ``` getTheme(): StyleSheet ``` +Gets the active StyleSheet for the backpack theme. + ### setTheme ``` setTheme(theme: "DefaultTheme" | "LegacyTheme" | StyleSheet): () ``` +Configures the backpack theme with a StyleSheet. + ### getTopbarIcon ``` getTopbarIcon(): TopbarPlus.Icon ``` +Gets the TopbarPlus icon used to toggle the backpack. + ### openInventory ``` openInventory(): () ``` +Opens the inventory. + ### closeInventory ``` closeInventory(): () ``` +Closes the inventory. + ### isInventoryOpen ``` isInventoryOpen(): boolean ``` + +Returns `true` if the inventory is open. From 3c62f6c2d0b0a15384d578d51ceda7303a6e0934 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Fri, 24 Apr 2026 02:55:04 +0000 Subject: [PATCH 203/206] Cleanup linenums and toc Signed-off-by: GitHub --- mkdocs.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index 073a9556..eeedd918 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -59,9 +59,6 @@ markdown_extensions: - pymdownx.superfences - toc: permalink: true - toc_depth: 3 - - pymdownx.highlight: - linenums: true - pymdownx.emoji: emoji_index: !!python/name:material.extensions.emoji.twemoji emoji_generator: !!python/name:material.extensions.emoji.to_svg From 0fbbaa1b812140fbe812267f0c9dfa6066d4e2d0 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 25 Apr 2026 08:19:36 +0000 Subject: [PATCH 204/206] Add events API docs Signed-off-by: GitHub --- docs/api-reference.md | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/docs/api-reference.md b/docs/api-reference.md index 5785931e..c14c50ac 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -38,7 +38,9 @@ Configures the backpack theme with a StyleSheet. getTopbarIcon(): TopbarPlus.Icon ``` -Gets the TopbarPlus icon used to toggle the backpack. +Gets the [TopbarPlus icon] used to toggle the backpack. + + [TopbarPlus icon]: https://1foreverhd.github.io/TopbarPlus/api/ ### openInventory @@ -63,3 +65,33 @@ isInventoryOpen(): boolean ``` Returns `true` if the inventory is open. + +## Events + +### backpackItemAdded + +Fires when an item is added to the backpack. + +### backpackItemRemoved + +Fires when an item is removed from the backpack. + +### backpackItemEquipped + +Fires when an item is equipped. + +### backpackItemUnequipped + +Fires when an item is unequipped. + +### inventoryOpened + +Fires when the player opens the inventory or when [openInventory](#openinventory) is called. + +### inventoryClosed + +Fires when the player closes the inventory or when [closeInventory](#closeinventory) is called. + +### themeChanged + +Fires when the backpack theme is changed. From be8490112f6b123c4ff64544a920ef37a983c08d Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 25 Apr 2026 08:26:06 +0000 Subject: [PATCH 205/206] Clear index Signed-off-by: GitHub --- docs/index.md | 78 +-------------------------------------------------- 1 file changed, 1 insertion(+), 77 deletions(-) diff --git a/docs/index.md b/docs/index.md index 162e07c4..303b5de2 100644 --- a/docs/index.md +++ b/docs/index.md @@ -3,87 +3,11 @@ margin: 4em 0; text-align: center; } - - /* Fix iframe background transparency */ - iframe { - color-scheme: light; - } -Satchel is a modern open-source alternative to Roblox's default backpack. - -Satchel aims to be more customizable and easier to use than the default backpack while still having a "vanilla" feel. Installation of Satchel is as simple as dropping the module into your game and setting up a few properties if you like to customize it. It has a familiar feel and structure as to the default backpack for ease of use for both developers and players. - -This documentation will allow you to install Satchel and learn about how to script using Satchel. - - - -
- -
- ---- - -
- -- :material-clock-fast:{ .lg .middle } __Fast and easy installation__ - - --- - - Drag and drop installation from the [Creator Store] or [GitHub Releases] - - [:material-arrow-right: Installation](installation.md) - - [Creator Store]: https://create.roblox.com/store/asset/13947506401 - [GitHub Releases]: https://github.com/ryanlua/satchel/releases - -- :material-devices:{ .lg .middle } __Full device support__ - - --- - - Compatible with computer, phone, tablet, console, and VR - - [:material-arrow-right: Platforms](platforms.md) - -- :material-toolbox-outline:{ .lg .middle } __Highly customizable__ - - --- - - Change colors, fonts, and more using [instance attributes] - - [:material-arrow-right: Customization](usage.md#customization) - - [instance attributes]: https://create.roblox.com/docs/studio/instance-attributes - -- :material-scale-balance:{ .lg .middle } __Free and open-source__ - - --- - - Open source for everyone to use and available on [GitHub] - - [:material-arrow-right: License](https://github.com/ryanlua/satchel#MPL-2.0-1-ov-file) - - [GitHub]: https://github.com/ryanlua/satchel - -
- - - ---- - ## Our Sponsors -Special thanks for our sponsors for supporting Satchel and it's future development. We distribute Satchel and provide updates for free, for anyone to use or modify. +Special thanks to our sponsors for supporting Satchel and its future development. We distribute Satchel and provide updates for free, for anyone to use or modify.
From a5b3fe2c2cf6eb6159f1b2ed4a38818bf8614399 Mon Sep 17 00:00:00 2001 From: Ryan Luu Date: Sat, 25 Apr 2026 08:40:40 +0000 Subject: [PATCH 206/206] Add type docs for events Signed-off-by: GitHub --- docs/api-reference.md | 28 ++++++++++++++++++++++++++++ src/Api/setTheme.luau | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/docs/api-reference.md b/docs/api-reference.md index c14c50ac..b3c5f9df 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -70,28 +70,56 @@ Returns `true` if the inventory is open. ### backpackItemAdded +``` +backpackItemAdded(item: BackpackItem): BindableEvent +``` + Fires when an item is added to the backpack. ### backpackItemRemoved +``` +backpackItemRemoved(item: BackpackItem): BindableEvent +``` + Fires when an item is removed from the backpack. ### backpackItemEquipped +``` +backpackItemEquipped(item: BackpackItem): BindableEvent +``` + Fires when an item is equipped. ### backpackItemUnequipped +``` +backpackItemUnequipped(item: BackpackItem): BindableEvent +``` + Fires when an item is unequipped. ### inventoryOpened +``` +inventoryOpened(): BindableEvent +``` + Fires when the player opens the inventory or when [openInventory](#openinventory) is called. ### inventoryClosed +``` +inventoryClosed(): BindableEvent +``` + Fires when the player closes the inventory or when [closeInventory](#closeinventory) is called. ### themeChanged +``` +themeChanged(newTheme: StyleSheet, oldTheme: StyleSheet): BindableEvent +``` + Fires when the backpack theme is changed. diff --git a/src/Api/setTheme.luau b/src/Api/setTheme.luau index 7aaf7133..dfbb4d9b 100644 --- a/src/Api/setTheme.luau +++ b/src/Api/setTheme.luau @@ -14,7 +14,7 @@ const function setTheme(theme: DefaultThemes | StyleSheet): () const newTheme: StyleSheet = if typeof(theme) == "string" then styleSheets:WaitForChild(theme) :: StyleSheet else theme currentTheme.StyleSheet = newTheme - bindableEvents.ThemeChanged:Fire(newTheme) + bindableEvents.ThemeChanged:Fire(newTheme, currentTheme.StyleSheet) end return setTheme