azul-sync 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/.gitattributes +1 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +31 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  4. package/README.md +142 -0
  5. package/dist/build.d.ts +19 -0
  6. package/dist/build.d.ts.map +1 -0
  7. package/dist/build.js +92 -0
  8. package/dist/build.js.map +1 -0
  9. package/dist/cli.d.ts +3 -0
  10. package/dist/cli.d.ts.map +1 -0
  11. package/dist/cli.js +397 -0
  12. package/dist/cli.js.map +1 -0
  13. package/dist/config.d.ts +26 -0
  14. package/dist/config.d.ts.map +1 -0
  15. package/dist/config.js +105 -0
  16. package/dist/config.js.map +1 -0
  17. package/dist/fs/fileWriter.d.ts +100 -0
  18. package/dist/fs/fileWriter.d.ts.map +1 -0
  19. package/dist/fs/fileWriter.js +342 -0
  20. package/dist/fs/fileWriter.js.map +1 -0
  21. package/dist/fs/treeManager.d.ts +84 -0
  22. package/dist/fs/treeManager.d.ts.map +1 -0
  23. package/dist/fs/treeManager.js +365 -0
  24. package/dist/fs/treeManager.js.map +1 -0
  25. package/dist/fs/watcher.d.ts +39 -0
  26. package/dist/fs/watcher.d.ts.map +1 -0
  27. package/dist/fs/watcher.js +120 -0
  28. package/dist/fs/watcher.js.map +1 -0
  29. package/dist/index.d.ts +61 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +349 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/ipc/httpPolling.d.ts +56 -0
  34. package/dist/ipc/httpPolling.d.ts.map +1 -0
  35. package/dist/ipc/httpPolling.js +171 -0
  36. package/dist/ipc/httpPolling.js.map +1 -0
  37. package/dist/ipc/messages.d.ts +112 -0
  38. package/dist/ipc/messages.d.ts.map +1 -0
  39. package/dist/ipc/messages.js +5 -0
  40. package/dist/ipc/messages.js.map +1 -0
  41. package/dist/ipc/server.d.ts +50 -0
  42. package/dist/ipc/server.d.ts.map +1 -0
  43. package/dist/ipc/server.js +168 -0
  44. package/dist/ipc/server.js.map +1 -0
  45. package/dist/pack.d.ts +19 -0
  46. package/dist/pack.d.ts.map +1 -0
  47. package/dist/pack.js +225 -0
  48. package/dist/pack.js.map +1 -0
  49. package/dist/push.d.ts +43 -0
  50. package/dist/push.d.ts.map +1 -0
  51. package/dist/push.js +532 -0
  52. package/dist/push.js.map +1 -0
  53. package/dist/rojo.d.ts +9 -0
  54. package/dist/rojo.d.ts.map +1 -0
  55. package/dist/rojo.js +114 -0
  56. package/dist/rojo.js.map +1 -0
  57. package/dist/snapshot/rojo.d.ts +39 -0
  58. package/dist/snapshot/rojo.d.ts.map +1 -0
  59. package/dist/snapshot/rojo.js +364 -0
  60. package/dist/snapshot/rojo.js.map +1 -0
  61. package/dist/snapshot.d.ts +23 -0
  62. package/dist/snapshot.d.ts.map +1 -0
  63. package/dist/snapshot.js +132 -0
  64. package/dist/snapshot.js.map +1 -0
  65. package/dist/sourcemap/generator.d.ts +78 -0
  66. package/dist/sourcemap/generator.d.ts.map +1 -0
  67. package/dist/sourcemap/generator.js +351 -0
  68. package/dist/sourcemap/generator.js.map +1 -0
  69. package/dist/sourcemap/propertyLoader.d.ts +19 -0
  70. package/dist/sourcemap/propertyLoader.d.ts.map +1 -0
  71. package/dist/sourcemap/propertyLoader.js +131 -0
  72. package/dist/sourcemap/propertyLoader.js.map +1 -0
  73. package/dist/util/id.d.ts +9 -0
  74. package/dist/util/id.d.ts.map +1 -0
  75. package/dist/util/id.js +14 -0
  76. package/dist/util/id.js.map +1 -0
  77. package/dist/util/log.d.ts +13 -0
  78. package/dist/util/log.d.ts.map +1 -0
  79. package/dist/util/log.js +51 -0
  80. package/dist/util/log.js.map +1 -0
  81. package/docs/assets/azul-logo.pdn +0 -0
  82. package/docs/assets/logo-200px.png +0 -0
  83. package/docs/assets/logo.png +0 -0
  84. package/docs/assets/plugin/toolbox.png +0 -0
  85. package/docs/assets/synced.png +0 -0
  86. package/package.json +41 -0
  87. package/plugin/README.md +54 -0
  88. package/plugin/sourcemap.json +264 -0
  89. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/Actor/AzulSync.server.luau +905 -0
  90. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/AzulService.luau +1010 -0
  91. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/Config.luau +29 -0
  92. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/Enums.luau +11 -0
  93. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/CollapsibleTitledSection.luau +214 -0
  94. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/ColorPicker.luau +360 -0
  95. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/CustomTextButton.luau +170 -0
  96. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/DropdownMenu.luau +363 -0
  97. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/HorizontalLine.luau +43 -0
  98. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/ImageButtonWithText.luau +181 -0
  99. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledCheckbox.luau +295 -0
  100. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledColorInputPicker.luau +294 -0
  101. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledMultiChoice.luau +163 -0
  102. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledNumberInput.luau +312 -0
  103. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledRadioButton.luau +55 -0
  104. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledSlider.luau +151 -0
  105. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledTextInput.luau +222 -0
  106. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/LabeledToggleButton.luau +73 -0
  107. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/StatefulImageButton.luau +125 -0
  108. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/VerticalScrollingFrame.luau +100 -0
  109. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/VerticalSpacer.luau +35 -0
  110. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/Components/VerticallyScalingListFrame.luau +107 -0
  111. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/GuiUtilities.luau +429 -0
  112. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/StudioWidgets/RbxGui.luau +4363 -0
  113. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/UI.luau +425 -0
  114. package/plugin/sync/ReplicatedFirst/AzulCompanionPlugin/WebSocketClient.luau +161 -0
  115. package/src/build.ts +120 -0
  116. package/src/cli.ts +496 -0
  117. package/src/config.ts +170 -0
  118. package/src/fs/fileWriter.ts +414 -0
  119. package/src/fs/treeManager.ts +458 -0
  120. package/src/fs/watcher.ts +142 -0
  121. package/src/index.ts +450 -0
  122. package/src/ipc/httpPolling.ts +214 -0
  123. package/src/ipc/messages.ts +159 -0
  124. package/src/ipc/server.ts +196 -0
  125. package/src/pack.ts +309 -0
  126. package/src/push.ts +726 -0
  127. package/src/snapshot/rojo.ts +467 -0
  128. package/src/snapshot.ts +161 -0
  129. package/src/sourcemap/generator.ts +504 -0
  130. package/src/sourcemap/propertyLoader.ts +195 -0
  131. package/src/util/id.ts +15 -0
  132. package/src/util/log.ts +94 -0
  133. package/tsconfig.json +24 -0
@@ -0,0 +1,29 @@
1
+ local Enums = require(script.Parent.Enums)
2
+
3
+ configTable = {
4
+ WS_URL = "ws://localhost:8080",
5
+ HEARTBEAT_INTERVAL = 30,
6
+ LIST_TYPE = Enums.listType.WHITELIST, -- or BLACKLIST
7
+ SERVICE_LIST = {
8
+ "Workspace",
9
+ "Lighting",
10
+ "ReplicatedFirst",
11
+ "ReplicatedStorage",
12
+ "ServerScriptService",
13
+ "ServerStorage",
14
+ "StarterGui",
15
+ "StarterPack",
16
+ "StarterPlayer",
17
+ "SoundService",
18
+ },
19
+
20
+ EXCLUDED_PARENTS = {
21
+ "ServerStorage.RecPlugins", -- Folder managed by "Eye" plugin. It updates the sourcemap thousands of times. We don't need to track this.
22
+ "Workspace.Surface Converter Storage", -- Folder managed by "Surface Converter" plugin. We don't need to track it.
23
+ },
24
+
25
+ DEBUG_MODE = false,
26
+ SILENT_MODE = false,
27
+ }
28
+
29
+ return configTable
@@ -0,0 +1,11 @@
1
+ return {
2
+ listType = {
3
+ WHITELIST = "WHITELIST",
4
+ BLACKLIST = "BLACKLIST",
5
+ },
6
+
7
+ scope = {
8
+ GLOBAL = "global",
9
+ PROJECT = "project",
10
+ },
11
+ }
@@ -0,0 +1,214 @@
1
+ ----------------------------------------
2
+ --
3
+ -- CollapsibleTitledSectionClass
4
+ --
5
+ -- Creates a section with a title label:
6
+ --
7
+ -- "SectionXXX"
8
+ -- "TitleBarVisual"
9
+ -- "Contents"
10
+ --
11
+ -- Requires "parent" and "sectionName" parameters and returns the section and its contentsFrame
12
+ -- The entire frame will resize dynamically as contents frame changes size.
13
+ --
14
+ -- "autoScalingList" is a boolean that defines wheter or not the content frame automatically resizes when children are added.
15
+ -- This is important for cases when you want minimize button to push or contract what is below it.
16
+ --
17
+ -- Both "minimizeable" and "minimizedByDefault" are false by default
18
+ -- These parameters define if the section will have an arrow button infront of the title label,
19
+ -- which the user may use to hide the section's contents
20
+ --
21
+ ----------------------------------------
22
+ GuiUtilities = require("../GuiUtilities")
23
+
24
+ local kArrowSpriteSheet = "rbxasset://textures/StudioSharedUI/arrowSpritesheet.png"
25
+ local kRightButtonRectSize = Vector2.new(12, 12)
26
+ local kRightButtonRectOffset = Vector2.new(12, 0)
27
+ local kDownButtonRectSize = Vector2.new(12, 12)
28
+ local kDownButtonRectOffset = Vector2.new(24, 0)
29
+
30
+ local kArrowSize = 9
31
+ local kDoubleClickTimeSec = 0.5
32
+
33
+ CollapsibleTitledSectionClass = {}
34
+ CollapsibleTitledSectionClass.__index = CollapsibleTitledSectionClass
35
+
36
+ --- CollapsibleTitledSectionClass constructor.
37
+ --- @param nameSuffix string -- The name suffix of the text input.
38
+ --- @param titleText string -- The title text.
39
+ --- @param autoScalingList boolean? -- Should it automatically update its size based on the content? Defaults to true.
40
+ --- @param minimizable boolean? -- Should it be minimizable? Defaults to true.
41
+ --- @param minimizedByDefault boolean? -- Should it start minimized? Defaults to true.
42
+ --- @paramm createTitleBar boolean? -- Should it create a title bar? Defaults to true.
43
+ --- @return CollapsibleTitledSectionClass -- The CollapsibleTitledSection class object.
44
+ function CollapsibleTitledSectionClass.new(
45
+ nameSuffix: string,
46
+ titleText: string,
47
+ autoScalingList: boolean?,
48
+ minimizable: boolean?,
49
+ minimizedByDefault: boolean?,
50
+ createTitleBar: boolean?
51
+ )
52
+ local self = {}
53
+ setmetatable(self, CollapsibleTitledSectionClass)
54
+
55
+ self._minimized = minimizedByDefault == true
56
+ self._minimizable = minimizable == true
57
+ self._createTitleBar = createTitleBar == nil or createTitleBar == true
58
+
59
+ self._titleBarHeight = GuiUtilities.kTitleBarHeight
60
+
61
+ local frame = Instance.new("Frame")
62
+ frame.Name = "CTSection" .. nameSuffix
63
+ frame.BackgroundTransparency = 1
64
+ self._frame = frame
65
+
66
+ local uiListLayout = Instance.new("UIListLayout")
67
+ uiListLayout.SortOrder = Enum.SortOrder.LayoutOrder
68
+ uiListLayout.Parent = frame
69
+ self._uiListLayout = uiListLayout
70
+
71
+ local contentsFrame = Instance.new("Frame")
72
+ contentsFrame.Name = "Contents"
73
+ contentsFrame.BackgroundTransparency = 1
74
+ contentsFrame.Size = UDim2.new(1, 0, 0, 1)
75
+ contentsFrame.Position = UDim2.new(0, 0, 0, 0)
76
+ contentsFrame.Parent = frame
77
+ contentsFrame.LayoutOrder = 2
78
+ GuiUtilities.syncGuiElementBackgroundColor(contentsFrame)
79
+
80
+ self._contentsFrame = contentsFrame
81
+
82
+ uiListLayout:GetPropertyChangedSignal("AbsoluteContentSize"):Connect(function()
83
+ self:_UpdateSize()
84
+ end)
85
+ self:_UpdateSize()
86
+
87
+ if self._createTitleBar then self:_CreateTitleBar(titleText) end
88
+ self:SetCollapsedState(self._minimized)
89
+
90
+ self._autoScalingList = autoScalingList == true
91
+ if self._autoScalingList then GuiUtilities.MakeFrameAutoScalingList(self:GetContentsFrame()) end
92
+
93
+ return self
94
+ end
95
+
96
+ --- Gets the frame of this Collapsible Section itself.
97
+ --- @return Frame This Collapsible Section frame.
98
+ function CollapsibleTitledSectionClass:GetSectionFrame(): Frame
99
+ return self._frame
100
+ end
101
+
102
+ --- Gets the frame that contains everything that is inside this Collapsible Section.
103
+ --- @return Frame The frame that contains everything inside this Collapsible Section.
104
+ function CollapsibleTitledSectionClass:GetContentsFrame(): Frame
105
+ return self._contentsFrame
106
+ end
107
+
108
+ function CollapsibleTitledSectionClass:_UpdateSize()
109
+ local totalSize = self._uiListLayout.AbsoluteContentSize.Y
110
+ self._frame.Size = UDim2.new(1, 0, 0, totalSize)
111
+ end
112
+
113
+ function CollapsibleTitledSectionClass:_UpdateMinimizeButton()
114
+ -- We can't rotate it because rotated images don't get clipped by parents.
115
+ -- This is all in a scroll widget.
116
+ -- :(
117
+ if self._minimized then
118
+ self._minimizeButton.Image = kArrowSpriteSheet
119
+ self._minimizeButton.ImageRectSize = kRightButtonRectSize
120
+ self._minimizeButton.ImageRectOffset = kRightButtonRectOffset
121
+ else
122
+ self._minimizeButton.Image = kArrowSpriteSheet
123
+ self._minimizeButton.ImageRectSize = kDownButtonRectSize
124
+ self._minimizeButton.ImageRectOffset = kDownButtonRectOffset
125
+ end
126
+ end
127
+
128
+ --- Sets the collapsed state. Whether or not its open and showing its contents.
129
+ --- @param state boolean -- A boolean representing the state to set.
130
+ function CollapsibleTitledSectionClass:SetCollapsedState(state: boolean)
131
+ if not self._minimizable then return end
132
+ self._minimized = state
133
+ self._contentsFrame.Visible = not state
134
+ self:_UpdateMinimizeButton()
135
+ self:_UpdateSize()
136
+ end
137
+
138
+ function CollapsibleTitledSectionClass:_ToggleCollapsedState()
139
+ if not self._minimizable then return end
140
+ self:SetCollapsedState(not self._minimized)
141
+ end
142
+
143
+ function CollapsibleTitledSectionClass:_CreateTitleBar(titleText)
144
+ local titleTextOffset = self._titleBarHeight
145
+
146
+ local titleBar = Instance.new("ImageButton")
147
+ titleBar.AutoButtonColor = false
148
+ titleBar.Name = "TitleBarVisual"
149
+ titleBar.BorderSizePixel = 0
150
+ titleBar.Position = UDim2.new(0, 0, 0, 0)
151
+ titleBar.Size = UDim2.new(1, 0, 0, self._titleBarHeight)
152
+ titleBar.Parent = self._frame
153
+ titleBar.LayoutOrder = 1
154
+ titleBar.BorderMode = Enum.BorderMode.Middle
155
+ titleBar.BorderSizePixel = 1
156
+ GuiUtilities.syncGuiElementTitleColor(titleBar)
157
+ GuiUtilities.syncGuiElementBorderColor(titleBar)
158
+
159
+ local titleLabel = Instance.new("TextLabel")
160
+ titleLabel.Name = "TitleLabel"
161
+ titleLabel.BackgroundTransparency = 1
162
+ titleLabel.Font = Enum.Font.SourceSansBold --todo: input spec font
163
+ titleLabel.TextSize = 15 --todo: input spec font size
164
+ titleLabel.TextXAlignment = Enum.TextXAlignment.Left
165
+ titleLabel.Text = titleText
166
+ titleLabel.Position = UDim2.new(0, titleTextOffset, 0, 0)
167
+ titleLabel.Size = UDim2.new(1, -titleTextOffset, 1, GuiUtilities.kTextVerticalFudge)
168
+ titleLabel.Parent = titleBar
169
+ GuiUtilities.syncGuiElementFontColor(titleLabel)
170
+
171
+ self._minimizeButton = Instance.new("ImageButton")
172
+ self._minimizeButton.Name = "MinimizeSectionButton"
173
+ self._minimizeButton.Image = kArrowSpriteSheet
174
+ self._minimizeButton.ImageRectSize = kRightButtonRectSize
175
+ self._minimizeButton.ImageRectOffset = kRightButtonRectOffset
176
+ self._minimizeButton.Size = UDim2.new(0, kArrowSize, 0, kArrowSize)
177
+ self._minimizeButton.AnchorPoint = Vector2.new(0.5, 0.5)
178
+ self._minimizeButton.Position = UDim2.new(0, self._titleBarHeight * 0.5, 0, self._titleBarHeight * 0.5)
179
+ self._minimizeButton.BackgroundTransparency = 1
180
+ self._minimizeButton.Visible = self._minimizable -- only show when minimizable
181
+ GuiUtilities.syncGuiElementColorCustom(
182
+ self._minimizeButton,
183
+ "ImageColor3",
184
+ Enum.StudioStyleGuideColor.ScriptText,
185
+ Enum.StudioStyleGuideModifier.Default
186
+ )
187
+
188
+ self._minimizeButton.MouseButton1Down:Connect(function()
189
+ self:_ToggleCollapsedState()
190
+ end)
191
+ self:_UpdateMinimizeButton()
192
+ self._minimizeButton.Parent = titleBar
193
+
194
+ self._latestClickTime = 0
195
+ titleBar.MouseButton1Down:Connect(function()
196
+ local now = tick()
197
+ if now - self._latestClickTime < kDoubleClickTimeSec then
198
+ self:_ToggleCollapsedState()
199
+ self._latestClickTime = 0
200
+ else
201
+ self._latestClickTime = now
202
+ end
203
+ end)
204
+ end
205
+
206
+ --- Adds a child frame to the contents section of the collapsible titled section.
207
+ --- @param childFrame GuiObject -- The GUI object to add to the contents frame.
208
+ --- @param layoutOrder number? -- Optional layout order to assign to the child frame.
209
+ function CollapsibleTitledSectionClass:AddChild(childFrame: GuiObject, layoutOrder: number?)
210
+ if layoutOrder then childFrame.LayoutOrder = layoutOrder end
211
+ childFrame.Parent = self._contentsFrame
212
+ end
213
+
214
+ return CollapsibleTitledSectionClass
@@ -0,0 +1,360 @@
1
+ ----------------------------------------
2
+ --
3
+ -- ColorPicker.lua
4
+ --
5
+ -- Creates a frame containing a color picker.
6
+ --
7
+ ----------------------------------------
8
+ GuiUtilities = require("../GuiUtilities")
9
+
10
+ local CustomTextButton = require("./CustomTextButton")
11
+ local VerticallyScalingListFrame = require("./VerticallyScalingListFrame")
12
+
13
+ local kColorPickedLabelHeight = 20
14
+
15
+ local ColorPickerClass = {}
16
+ ColorPickerClass.__index = ColorPickerClass
17
+
18
+ --- ColorPickerClass constructor.
19
+ --- @param nameSuffix string -- Suffix to append to the color picker's name.
20
+ --- @return ColorPickerClass -- A new instance of the color picker class.
21
+ function ColorPickerClass.new(nameSuffix: string)
22
+ local self = setmetatable({}, ColorPickerClass)
23
+
24
+ self._cancelFunction = nil
25
+ self._confirmFunction = nil
26
+ self._valueChangedFunction = nil
27
+
28
+ local frame = Instance.new("Frame")
29
+ frame.Name = "ClPck " .. nameSuffix
30
+ frame.BackgroundColor3 = Color3.fromRGB(53, 53, 53)
31
+ frame.BorderSizePixel = 0
32
+ frame.Size = UDim2.fromOffset(170, 186)
33
+ GuiUtilities.syncGuiElementBackgroundColor(frame)
34
+
35
+ local colorSpectrum = Instance.new("ImageButton")
36
+ colorSpectrum.Name = "ColorSpectrum"
37
+ colorSpectrum.AutoButtonColor = false
38
+ colorSpectrum.BackgroundColor3 = Color3.new(1, 1, 1)
39
+ colorSpectrum.Image = "rbxassetid://18967417547"
40
+ colorSpectrum.Position = UDim2.new(0, 15, 0, 7)
41
+ colorSpectrum.Size = UDim2.new(0, 111, 0, 111)
42
+ colorSpectrum.BorderSizePixel = 1
43
+ colorSpectrum.Parent = frame
44
+ GuiUtilities.syncGuiElementBorderColor(colorSpectrum)
45
+
46
+ local colorBrightness = Instance.new("ImageButton")
47
+ colorBrightness.Name = "ColorBrightness"
48
+ colorBrightness.AnchorPoint = Vector2.new(0.5, 0)
49
+ colorBrightness.AutoButtonColor = false
50
+ colorBrightness.BackgroundColor3 = Color3.new(1, 1, 1)
51
+ colorBrightness.Image = ""
52
+ colorBrightness.Position = UDim2.new(1, -20, 0, 7)
53
+ colorBrightness.Size = UDim2.new(0, 16, 0, 107)
54
+ colorBrightness.BorderSizePixel = 1
55
+ colorBrightness.Parent = frame
56
+ GuiUtilities.syncGuiElementBorderColor(colorBrightness)
57
+
58
+ local colorBrightnessKnob = Instance.new("Frame")
59
+ colorBrightnessKnob.Name = "Knob"
60
+ colorBrightnessKnob.AnchorPoint = Vector2.new(0.5, 0)
61
+ colorBrightnessKnob.BackgroundColor3 = Color3.new(1, 1, 1)
62
+ colorBrightnessKnob.BorderColor3 = Color3.new()
63
+ colorBrightnessKnob.BorderSizePixel = 0
64
+ colorBrightnessKnob.Position = UDim2.fromScale(0.5, 0)
65
+ colorBrightnessKnob.Size = UDim2.fromOffset(25, 10)
66
+ colorBrightnessKnob.Parent = colorBrightness
67
+
68
+ local uIGradient = Instance.new("UIGradient")
69
+ uIGradient.Name = "UIGradient"
70
+ uIGradient.Rotation = -90
71
+ uIGradient.Color = ColorSequence.new({
72
+ ColorSequenceKeypoint.new(0, Color3.new(0, 0, 0)),
73
+ ColorSequenceKeypoint.new(1, Color3.new(1, 1, 1)),
74
+ })
75
+ uIGradient.Parent = colorBrightness
76
+
77
+ local uiStroke = Instance.new("UIStroke")
78
+ uiStroke.ApplyStrokeMode = Enum.ApplyStrokeMode.Border
79
+ uiStroke.Parent = colorBrightnessKnob
80
+
81
+ local uiCorner = Instance.new("UICorner")
82
+ uiCorner.CornerRadius = UDim.new(0, 4)
83
+ uiCorner.Parent = colorBrightnessKnob
84
+
85
+ local cross = Instance.new("ImageLabel")
86
+ cross.Name = "CrossIcon"
87
+ cross.AnchorPoint = Vector2.new(0.5, 0.5)
88
+ cross.BackgroundTransparency = 1
89
+ cross.Image = "rbxassetid://15929013661"
90
+ cross.Position = UDim2.fromScale(0, 0)
91
+ cross.Size = UDim2.fromOffset(20, 20)
92
+ cross.Parent = colorSpectrum
93
+
94
+ local buttonsContainer = Instance.new("Frame")
95
+ buttonsContainer.Name = "ButtonsContainer"
96
+ buttonsContainer.AnchorPoint = Vector2.new(0.5, 1)
97
+ buttonsContainer.BackgroundColor3 = Color3.fromRGB(169, 255, 129)
98
+ buttonsContainer.BackgroundTransparency = 1
99
+ buttonsContainer.BorderSizePixel = 0
100
+ buttonsContainer.Position = UDim2.fromScale(0.5, 1)
101
+ buttonsContainer.Size = UDim2.fromOffset(170, 36)
102
+ buttonsContainer.Parent = frame
103
+
104
+ local outputContainer = Instance.new("Frame")
105
+ outputContainer.Name = "OutputContainer"
106
+ outputContainer.AnchorPoint = Vector2.new(0.5, 1)
107
+ outputContainer.BackgroundTransparency = 1
108
+ outputContainer.BackgroundColor3 = Color3.fromRGB(40, 132, 181)
109
+ outputContainer.BorderSizePixel = 0
110
+ outputContainer.Position = UDim2.fromScale(0.5, 0.8)
111
+ outputContainer.Size = UDim2.fromOffset(170, 24)
112
+ outputContainer.Parent = frame
113
+
114
+ local colorPreviewBox = Instance.new("Frame")
115
+ colorPreviewBox.Name = "ColorPreview"
116
+ colorPreviewBox.AnchorPoint = Vector2.new(0, 0.5)
117
+ colorPreviewBox.BackgroundColor3 = Color3.new(1, 1, 1)
118
+ colorPreviewBox.Position = UDim2.new(0, 15, 0.5, 0)
119
+ colorPreviewBox.Size = UDim2.new(0, 18, 0, 18)
120
+ colorPreviewBox.Parent = outputContainer
121
+ GuiUtilities.syncGuiElementBorderColor(colorPreviewBox)
122
+
123
+ local colorRGBCode = Instance.new("TextBox")
124
+ colorRGBCode.Name = "ColorRGBCode"
125
+ colorRGBCode.AnchorPoint = Vector2.new(0, 0.5)
126
+ colorRGBCode.BackgroundColor3 = Color3.fromRGB(61, 255, 232)
127
+ colorRGBCode.BorderColor3 = Color3.fromRGB(34, 34, 34)
128
+ colorRGBCode.BorderSizePixel = 1
129
+ colorRGBCode.ClearTextOnFocus = false
130
+ colorRGBCode.Font = Enum.Font.SourceSans
131
+ colorRGBCode.Position = UDim2.new(0, 36, 0.5, 0)
132
+ colorRGBCode.Size = UDim2.fromOffset(62, 20)
133
+ colorRGBCode.Text = "255,255,255"
134
+ colorRGBCode.TextColor3 = Color3.fromRGB(204, 204, 204)
135
+ colorRGBCode.TextEditable = false
136
+ colorRGBCode.TextSize = 15
137
+ colorRGBCode.Parent = outputContainer
138
+ GuiUtilities.syncGuiElementFontColor(colorRGBCode)
139
+ GuiUtilities.syncGuiElementInputFieldColor(colorRGBCode)
140
+ GuiUtilities.syncGuiElementBorderColor(colorRGBCode)
141
+
142
+ local colorHexCode = Instance.new("TextBox")
143
+ colorHexCode.Name = "ColorHexCode"
144
+ colorHexCode.AnchorPoint = Vector2.new(0, 0.5)
145
+ colorHexCode.BackgroundColor3 = Color3.fromRGB(61, 255, 232)
146
+ colorHexCode.BorderColor3 = Color3.fromRGB(34, 34, 34)
147
+ colorHexCode.BorderSizePixel = 1
148
+ colorHexCode.ClearTextOnFocus = false
149
+ colorHexCode.Font = Enum.Font.SourceSans
150
+ colorHexCode.Position = UDim2.new(0, 101, 0.5, 0)
151
+ colorHexCode.Size = UDim2.fromOffset(55, 20)
152
+ colorHexCode.Text = "#FFFFFF"
153
+ colorHexCode.TextColor3 = Color3.fromRGB(204, 204, 204)
154
+ colorHexCode.TextEditable = false
155
+ colorHexCode.TextSize = 15
156
+ colorHexCode.Parent = outputContainer
157
+ GuiUtilities.syncGuiElementFontColor(colorHexCode)
158
+ GuiUtilities.syncGuiElementInputFieldColor(colorHexCode)
159
+ GuiUtilities.syncGuiElementBorderColor(colorHexCode)
160
+
161
+ colorSpectrum.InputBegan:Connect(function (inputObject: InputObject)
162
+ if inputObject.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
163
+ self._dragging = true
164
+ self:_OnColorSpectrumClick(inputObject)
165
+ end)
166
+
167
+ colorSpectrum.InputChanged:Connect(function (inputObject: InputObject)
168
+ if not self._dragging then return end
169
+ self:_OnColorSpectrumClick(inputObject)
170
+ end)
171
+
172
+ colorSpectrum.InputEnded:Connect(function (inputObject: InputObject)
173
+ if inputObject.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
174
+ self._dragging = false
175
+ end)
176
+
177
+ colorBrightness.InputBegan:Connect(function (inputObject: InputObject)
178
+ if inputObject.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
179
+ self._draggingBrightness = true
180
+ self:_OnBrightnessSliderClick(inputObject)
181
+ end)
182
+
183
+ colorBrightness.InputChanged:Connect(function (inputObject: InputObject)
184
+ if not self._draggingBrightness then return end
185
+ self:_OnBrightnessSliderClick(inputObject)
186
+ end)
187
+
188
+ colorBrightness.InputEnded:Connect(function (inputObject: InputObject)
189
+ if inputObject.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
190
+ self._draggingBrightness = false
191
+ end)
192
+
193
+ local verticallyScalingFrame = VerticallyScalingListFrame.new("suffix")
194
+ verticallyScalingFrame:GetFrame().Parent = buttonsContainer
195
+ verticallyScalingFrame:GetFrame().AnchorPoint = Vector2.new(0, 0.5)
196
+ verticallyScalingFrame:GetFrame().Position = UDim2.fromScale(0, 0.5)
197
+ verticallyScalingFrame:SetHorizontalAlignment(Enum.HorizontalAlignment.Center)
198
+ verticallyScalingFrame:SetVerticalAlignment(Enum.VerticalAlignment.Center)
199
+ verticallyScalingFrame:SetFillDirection(Enum.FillDirection.Horizontal)
200
+ verticallyScalingFrame:SetLayoutPadding(UDim.new(0, 5))
201
+
202
+ local buttonConfirm = CustomTextButton.new("confirm", "Confirm", true)
203
+ local buttonCancel = CustomTextButton.new("cancel", "Cancel", true)
204
+
205
+ verticallyScalingFrame:AddChild(buttonConfirm:GetFrame())
206
+ verticallyScalingFrame:AddChild(buttonCancel:GetFrame())
207
+
208
+ self._frame = frame
209
+ self._colorSpectrum = colorSpectrum
210
+ self._colorPreviewBox = colorPreviewBox
211
+ self._colorCodeBoxRGB = colorRGBCode
212
+ self._colorCodeBoxHex = colorHexCode
213
+ self._colorBrightnessSlider = colorBrightness
214
+ self._colorBrightnessKnob = colorBrightnessKnob
215
+ self._colorCross = cross
216
+ self._buttonCancel = buttonCancel
217
+ self._buttonConfirm = buttonConfirm
218
+
219
+ self._colorPicked = Color3.new(1,1,1) :: Color3
220
+ self._colorPickedRGBCode = "255,255,255"
221
+ self._colorPickedHexCode = "#FFFFFF"
222
+
223
+ self._dragging = false
224
+ self._draggingBrightness = false
225
+
226
+ self._hsvHue = 1
227
+ self._hsvSat = 1
228
+ self._hsvVal = 1
229
+
230
+ return self
231
+ end
232
+
233
+ function ColorPickerClass:_OnColorSpectrumClick(inputObject: InputObject)
234
+ -- detect clicked color code based on the click position in the color spectrum image
235
+ local relX: number, relY:number = GuiUtilities.GetClickOffsetFromObject(inputObject, self._colorSpectrum)
236
+ if relX >= 0 and relX <= 1 and relY >= 0 and relY <= 1 then
237
+ self._hsvHue = relX
238
+ self._hsvSat = 1 - relY
239
+ self:_CommitColorChange()
240
+ self:_UpdateBrightnessSlider()
241
+ self:_UpdateColorCross()
242
+ end
243
+ end
244
+
245
+ function ColorPickerClass:_OnBrightnessSliderClick(inputObject: InputObject)
246
+ local _, relY = GuiUtilities.GetClickOffsetFromObject(inputObject, self._colorBrightnessSlider)
247
+ self._hsvVal = 1 - relY
248
+ self:_UpdateBrightnessSlider()
249
+ self:_CommitColorChange()
250
+ end
251
+
252
+ function ColorPickerClass:_CommitColorChange(color: Color3?)
253
+ -- Applies and commits a new color to the picker.
254
+ -- If a Color3 parameter is provided, updates internal HSV values accordingly. Used by manually setting the value.
255
+ -- Otherwise, generates a color from current HSV state. Used by interacting with the picker.
256
+ -- Also updates UI elements and triggers the value changed callback if set.
257
+ if color then
258
+ self._colorPicked = color
259
+ local h, s, v = color:ToHSV()
260
+ self._hsvHue = h
261
+ self._hsvSat = s
262
+ self._hsvVal = v
263
+ else
264
+ self._colorPicked = Color3.fromHSV(self._hsvHue, self._hsvSat, self._hsvVal)
265
+ end
266
+
267
+ self:_UpdateColorCodeLabel()
268
+ self:_UpdateColorPreviewBox()
269
+ if self._valueChangedFunction then -- fire value changed function
270
+ self._valueChangedFunction(self._colorPicked)
271
+ end
272
+ end
273
+
274
+ function ColorPickerClass:_UpdateColorCross()
275
+ -- positions and paint the color cross
276
+ self._colorCross.Position = UDim2.fromScale(self._hsvHue, 1 - self._hsvSat)
277
+ self._colorCross.ImageColor3 = if 1 - self._hsvSat < 0.4 then Color3.new(1,1,1) else Color3.new(0,0,0)
278
+ end
279
+
280
+ function ColorPickerClass:_UpdateBrightnessSlider()
281
+ self._colorBrightnessKnob.Position = UDim2.new(0.5, 0, 1 - self._hsvVal, 0)
282
+ self._colorBrightnessSlider.UIGradient.Color = ColorSequence.new({
283
+ ColorSequenceKeypoint.new(0, Color3.new(0, 0, 0)),
284
+ ColorSequenceKeypoint.new(1, Color3.fromHSV(self._hsvHue, self._hsvSat, 1)),
285
+ })
286
+ end
287
+
288
+ function ColorPickerClass:_UpdateColorCodeLabel()
289
+ -- generate a color code string like this: R,G,B #HEX
290
+ local R = math.clamp(math.round(self._colorPicked.R * 255), 0, 255)
291
+ local G = math.clamp(math.round(self._colorPicked.G * 255), 0, 255)
292
+ local B = math.clamp(math.round(self._colorPicked.B * 255), 0, 255)
293
+ self._colorPickedHexCode = "#" .. string.upper(self._colorPicked:ToHex())
294
+ self._colorPickedRGBCode = ("%d,%d,%d"):format(R, G, B)
295
+ self._colorCodeBoxRGB.Text = self._colorPickedRGBCode
296
+ self._colorCodeBoxHex.Text = self._colorPickedHexCode
297
+ end
298
+
299
+ function ColorPickerClass:_UpdateColorPreviewBox()
300
+ self._colorPreviewBox.BackgroundColor3 = self._colorPicked
301
+ end
302
+
303
+ --- Sets the function to be called when the cancel button is clicked.
304
+ --- @param cf function -- A function to execute when cancel is pressed.
305
+ function ColorPickerClass:SetCancelFunction(cf: () -> ())
306
+ self._buttonCancel:SetClickedFunction(cf)
307
+ end
308
+
309
+ --- Sets the function to be called when the confirm button is clicked.
310
+ --- Passes the currently selected color to the callback.
311
+ --- @param cf function -- A function that takes the selected Color3 as a parameter.
312
+ function ColorPickerClass:SetConfirmFunction(cf: (chosenColor: Color3) -> ())
313
+ self._buttonConfirm:SetClickedFunction(function (...)
314
+ cf(self._colorPicked)
315
+ end)
316
+ end
317
+
318
+ --- Sets a callback function to be called when the color value changes.
319
+ --- Passing nil will remove the existing callback.
320
+ --- @param vcf (newValue: Color3) -> () | nil -- Function to call on color change, or nil to unbind.
321
+ function ColorPickerClass:SetValueChangedFunction(vcf: (newValue: Color3) -> () | nil)
322
+ self._valueChangedFunction = vcf
323
+ end
324
+
325
+ --- Returns the main UI frame of the color picker.
326
+ --- @return Frame -- The root frame containing the color picker UI.
327
+ function ColorPickerClass:GetFrame(): Frame
328
+ return self._frame
329
+ end
330
+
331
+ --- Gets the currently selected color in the color picker.
332
+ --- @return Color3 -- The current color selection.
333
+ function ColorPickerClass:GetValue(): Color3
334
+ return self._colorPicked
335
+ end
336
+
337
+ --- Sets the currently selected color in the color picker.
338
+ --- @param newValue Color3 -- The color to set.
339
+ function ColorPickerClass:SetValue(newValue: Color3)
340
+ self:_CommitColorChange(newValue)
341
+ self:_UpdateColorCross()
342
+ self:_UpdateBrightnessSlider()
343
+ end
344
+
345
+ --- Returns the currently picked color as a hex code string.
346
+ --- Example: "#FFFFFF" for white.
347
+ --- @return string -- The hex code representation of the picked color.
348
+ function ColorPickerClass:GetHexCode(): string
349
+ return self._colorPickedHexCode
350
+ end
351
+
352
+
353
+ --- Returns the currently picked color as an RGB string.
354
+ --- Example: "255,255,255" for white.
355
+ --- @return string -- The RGB string representation of the picked color.
356
+ function ColorPickerClass:GetRGBCode(): string
357
+ return self._colorPickedRGBCode
358
+ end
359
+
360
+ return ColorPickerClass