Step by Step Guide for Roblox Staff to modify AdjustmentSlider Component within Lua App Universal App

This is going to be a step by step tutorial to modify the Lua App Universal App “AdjustmentSlider” Component.

 

At the end it’s going to look something like this:


There were a few more things that I was trying to do, but I ended up not experimenting with that area, because I’d have to modify UIBlox for that, and this would increase the tutorial to much.

image

Purpose?

What’s the purpose of this tutorial? It’s only useful to Roblox. But they don’t even need this.

The purpose is that I can show what I wanted the Accessory Adjustment Editor to additionally include.

I might speedran this, but that what is achieved here, is explained.

 

A few things that may be interesting to you?

What does the Accessory Adjustment do?

Everytime you move the slider, it applies HumanoidDescription… uhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh

I guess it works… Though I think there was an alternate version, though at the end it’s math… so you could just alter the welds.

 

Notes

When I created this, I didn’t know the Slider had a props.textInputEnabled property that would bring a text input near the slider as well. :thinking:

UIBlox…
image

 

Let’s begin!

Open the following ModuleScript: AvatarExperience.AccessoryAdjustment.Components.AdjustmentSlider.

This is the only file we will be modifying.

Since things are different for me, the variable names will probably be different compared to what you (if you’re a Roblox Engineer) would see.

The table variable with the LimitKey, I named it AdjustmentTypeConstants as I had no clue what else it could be.

How to make the reset buttons

I won’t mention how I animated the Buttons, as I believe the way I choose to do it may be not ideal on how I control the behavior. But it was done with ReactOtter.

Basically

local ReactOtter = require(CorePackages.Packages.ReactOtter)
Summary
local function SliderImage(theme, adjustmentSliderType, iconSize, otherProps)
	local scaleEffectGoal, setScaleEffectGoal = React.useState(1)
	local scaleAnimValue, setGoal = ReactOtter.useAnimatedBinding(1)
	
	local function UIScale_Effect(props)
		return React.createElement("UIScale", {
			Scale = props.Scale
		})
	end
	
	React.useEffect(function()
		setGoal(ReactOtter.ease(scaleEffectGoal, {
			duration = 0.05,
			easingStyle = Enum.EasingStyle.Quad
		}))
	end, {scaleEffectGoal})

	
	local ImageSetComponent = React.createElement(ImageSetLabel, {
        Size = UDim2.new(0, iconSize, 0, iconSize), 
        BackgroundTransparency = 1, 
        Image = asset_cirle_21, 
        ImageColor3 = AdjustmentTypeConstants[adjustmentSliderType].Color, 
        ImageTransparency = theme.IconEmphasis.Transparency, 
        AnchorPoint = Vector2.new(0.5, 0.5), 
		Position = UDim2.new(0.5, 0, 0.5, 0),
		
		[React.Event.MouseButton1Click] = function()
		local defaultValue = Constants.DefaultSliderValues[adjustmentSliderType]

		otherProps.setSliderValuesCallback(defaultValue, adjustmentSliderType)
		otherProps.updateCharacterCallback(defaultValue, adjustmentSliderType)
	end,
		
		[React.Event.MouseButton1Down] = function()
			setScaleEffectGoal(0.7)
		end,

		[React.Event.MouseButton1Up] = function()
			setScaleEffectGoal(1)
		end,
		[React.Event.MouseLeave] = function()
			setScaleEffectGoal(1)
		end,
    }, {
        Letter = React.createElement("TextLabel", {
            Size = UDim2.new(1, -3, 1, -3), 
            BackgroundTransparency = 1, 
            Text = AdjustmentTypeConstants[adjustmentSliderType].Text, 
            TextScaled = true,
            FontFace = Constants.FontFace, 
            TextColor3 = Color3.new(1, 1, 1), 
            AnchorPoint = Vector2.new(0.5, 0.5), 
            Position = UDim2.new(0.5, 0, 0.5, 0), 
            ZIndex = 2
		}),
		
		UIScale = UIScale_Effect({
			Scale = scaleAnimValue
		})
	});
	

	return React.createElement("Frame", {
		BackgroundTransparency = 1,
		Size = UDim2.new(0, iconSize, 0, iconSize),
	}, ImageSetComponent)
end

First I replaced the ImageSetLabel with this

local ImageSetLabel = UIBlox.Core.ImageSet.ImageSetButton

Because buttons have clicking events.

The part that you want to add to the SliderImage is this.

[React.Event.MouseButton1Click] = function()
	local defaultValue = Constants.DefaultSliderValues[adjustmentSliderType]

	otherProps.setSliderValuesCallback(defaultValue, adjustmentSliderType)
	otherProps.updateCharacterCallback(defaultValue, adjustmentSliderType)
	--print(defaultValue, adjustmentSliderType)
end,
  1. At the end you need to go to createElement and pass the props
SliderImage = SliderImage(
	Theme,
	props.adjustmentSliderType,
	mapTokens.smallIconSize,
	props
)

Adding the Slider Text

NOTE: :warning:
When I created this thread, I didn’t know about props.textInputEnabled for UIBlox’s SystemSlider component. (Which is a more vanilla way to integrate a text input to the slider)

Nevermind the SliderTextInput uses the same percentage based values by default, which is not what I was aiming for.

If you want to do it through the props.textInputEnabled way, simply follow the details below.

Expand me for easier way
  1. At the location where the SystemSlider Component is being created through createElement. Within its props simply add this property.
textInputEnabled = true

That’s literally all…

 

 

Different way
  1. Put this somewhere at the top area of the script or something.
local SliderText_padding = 45
  1. Add this
local function SliderText(theme, adjustmentSliderType, sliderValue, otherProps)
	local style = useStyle()
	local tokens = style.Tokens
	
	local textFieldStyle = tokens.Component.TextField
	local selectionBorderThickness = tokens.Semantic.Stroke.Focus
	local iconSize = tokens.Semantic.Icon.Size.Small

	local curValue = sliderValue

	local textBoxRef = React.useRef(nil)
	
	local selectorLowerAdjustmentLimits = useSelector(selectLowerAdjustmentLimits);
	local selectorUpperAdjustmentLimits = useSelector(selectUpperAdjustmentLimits);

	return React.createElement("TextBox", {
		ref = textBoxRef,
		Text = curValue,

		[React.Event.FocusLost] = function(enterPressed)
			local AdjustmentKey = AdjustmentTypeConstants[adjustmentSliderType].AdjustmentKey;
			local LimitKey = AdjustmentTypeConstants[adjustmentSliderType].LimitKey;
			local lowerLimit = selectorLowerAdjustmentLimits[AdjustmentKey][LimitKey];
			local upperLimit = selectorUpperAdjustmentLimits[AdjustmentKey][LimitKey];
			
			local newValue = tonumber(textBoxRef.current.Text)
			
			-- Cap new value
			--newValue = math.max(lowerLimit, math.min(upperLimit, newValue))
			-- You can or maybe should use math.clamp instead of that there!!!
			newValue = math.clamp(newValue, lowerLimit, upperLimit)

			otherProps.setSliderValuesCallback(newValue, adjustmentSliderType)
			otherProps.updateCharacterCallback(newValue, adjustmentSliderType)
			--print(newValue, adjustmentSliderType)
		end,
		
		BackgroundTransparency = 1,
		ClearTextOnFocus = false,
		Font = textFieldStyle.Base.Field.Typography.Font,
		TextColor3 = textFieldStyle.Base.FieldValue.ContentColor.Color3,
		TextTransparency = textFieldStyle.Base.FieldValue.ContentColor.Transparency,
		TextSize = textFieldStyle.Base.Field.Typography.FontSize - 3,
		
		Size = UDim2.new(0, SliderText_padding, 0, 32),
		ClipsDescendants = true,
		LayoutOrder = 3,
	}, {
		React.createElement("UICorner", {
			CornerRadius = UDim.new(0, 6)
		}),
		
		React.createElement("UIStroke", {
			ApplyStrokeMode = Enum.ApplyStrokeMode.Border,
			Color = textFieldStyle.Base.Field.BorderColor.Color3,
			Thickness = 1,
			Transparency = textFieldStyle.Base.Field.BorderColor.Transparency,
		}),
	})
end
  1. Locate this line Slider = React.createElement(

  2. Within that createElement function, change width so it matches this

width = UDim.new(
	1,
	-mapTokens.padding - mapTokens.smallIconSize
	- (SliderText_padding - -16)
)

The reason why there's ``-16`` is because of the padding, and I don't know.
  1. Then within that same createElement add
SliderText = SliderText(
	Theme, adjustmentSliderType, props.sliderValue, props
)

 

 

And that should be it!

This is how you do it.

 

Conclusion

I am not sure if I should of have used otherProps to simply pass the props through. You only need the callbacks. And these two functions could have been moved else where.

Why did I not use the Text Field Component from UIBlox?

The reason is…
I didn’t want to modify UIBlox itself, it’s missing props, instead I just copied a portion of the UIBlox Text Component. I guess you could call it “Super Lite Version” of UIBlox’s Text Field Component.

Why did you not do X with the UI?

UIBlox props are the reason. And for this thread, I solely wanted to modify one file.

These callback functions… I don’t know what to think about them. They function and work, but maybe moving them somewhere else could be interesting.

 

Final Notes

This is just a sketch and an idea. I doubt anyone at Roblox would make these X Y Z buttons clickable, as it is a hidden feature otherwise. There’s no hint for it.

Instead, I’d put that Undo Button from the top right.

What I actually would do is the following:

  • Get rid of the X Y Z labels, and instead move them into the center of the slider circle.
  • Now, we have space to add a undo button and text field

e.g. the Slider like so

image

Additonally, I’d make the slider track fill bar start at the center. You may notice how in the video, the slider values had inconsistency between X Y Z.

Moving one fully to the right, would have said 0.25 while for the other Axis it would have said -0.25. This makes it a bit confusing, and I believe the solution would be to have the sliders different.

 

I’d want to experiment with that, but I probably won’t do it in the Universal App. I had to go through severe amount of pain to even get it to run on Studio and the amount of Memory that thing needs with the way on how I did it… is… catastrophic.

I’d also want to experiment with useMemo.

 

If you want to reset your position to 0 in vanilla ways, you can enable the following Fast Flags:

  • FFlagAXAASnapSliderToMiddle, to true
  • FIntAXAdjustmentSnapThreshold, default is 5

But I tried it and… I don’t trust it, I need to see the number.

And these flags are not even where all flags usually get stored at. Yet today that’s another Roblox mystery to me.

9 Likes