SmoothScroll Module [Superseded by Roblox Update 421]

In the module, there are a few prints commented out (Click, Drag, and two of Release)

Uncomment and see if Release gets printed


Nope, it doesn’t get printed (also I did uncomment it)

I have to go to work, but when I’m free I’ll look into the issue. Can you DM me your GUI? It might have to do with the layout and parenting.

Oh man, this is humiliating.
The bug was because I’d used autocomplete for a variable and I bumped the wrong one.

Uploaded the updated file. Sorry about that!

1 Like

I’ve now implemented this into Lua Learning (currently on front page) so I’ll get lots of user feedback and bug reports on it.

I hope it works!

Edit: 4 days later, no complaints so far. It was implemented on almost every ScrollingFrame in the game, so I’m taking this a confirmation of full functionality. Note that I am using the UIS edition, not the CAS. There’s no camera in my game, so there’s no downside for me. Steps to change your version to the UIS edition can be found below:

1 Like

I just implemented this into my game and a few players are complaining they can’t scroll?

I’m sorry to hear that!
Without more info, I can’t really help you?

My guess is that you’ve hit the ContextActionService sinking issue from earlier in this thread:

To avoid this, you’d want to replace the CAS binding with a UserInputService binding that ignores GameProcessed. Note that this means input will not be sunk, and scrolling might affect the camera.

Steps to change from CAS to UIS
  1. Remove lines 57-71:
	CAS:BindActionAtPriority("SmoothScroll", function(Name,State,Input)
		if DraggingBar then return Enum.ContextActionResult.Pass end
		local Processed = false
		for Frame, Info in pairs(Objects) do
			if Info.Hovering and Info.Visibility.Visible == true then
				Processed = true
				Info.Velocity = Info.Velocity - (Info.Sens * Input.Position.Z * (Info.Inverted and -1 or 1))
		return Processed and Enum.ContextActionResult.Sink or Enum.ContextActionResult.Pass
	end, false, 8000, Enum.UserInputType.MouseWheel)
  1. In that spot (from line 57) add the following:
	UIS.InputChanged:Connect(function(Input, GP)
		if --[[not GP and]] Input.UserInputType == Enum.UserInputType.MouseWheel and not DraggingBar then
			for Frame, Info in pairs(Objects) do
				if Info.Hovering and Info.Visibility.Visible == true then
					Info.Velocity = Info.Velocity - (Info.Sens * Input.Position.Z * (Info.Inverted and -1 or 1))
1 Like

Yeah I don’t want it to affect the camera :confused:
I tried to use it on a scrolling frame with buttons and It didn’t work so I had to disable it for that specific scrolling frame.

The smooth scrolling for the other scrolling frames work fine for me, but a few players sometimes aren’t able to scroll for some reason??

This is awesome! I’ve been using this in all of my ScrollingFrames, it is really smooth.

1 Like

I’m not sure why but I seem to be receiving an “invalid frame to smooth” when the frame I’m trying to do is a ScrollingFrame?

Oh nice! I’ve used this quite a bit now and it’s pretty good.
Thank you for making this :slightly_smiling_face:

1 Like

Roblox has recently released an API for trackpad gestures. As seen previously in this thread, trackpad users can only scroll via the drag bar with this module’s current state. I am working on adding proper trackpad support, and will then update this thread and the model.

I have a functioning prototype.

However, it falls into the problem of CAS vs. UIS that has been discussed throughout this thread. Because the API is currently UIS-only, there is no way for me to sink the input.
Because of this, this feature may have to wait until Roblox adds trackpad support into the CAS API as well. I have asked them about this, so we shall see.


The module is finally completely functional!

Everyone should go replace the module with this new version if they’ve been using it.


  • Trackpad support
  • Fixed issues with not scrolling in some cases
  • Fixed issues with affecting camera when scrolling a frame

Everyone make sure to thank @colbert2677 for he helped me test trackpad support and he solved the UIS/CAS issue.

Previous issues

If you remember earlier in the thread, we discussed these.

If the module uses UIS to scroll, the the scrolling input does not get sunk and will move the camera+any other wheel/pan events you’ve connected.

If the module uses CAS to scroll, we can sink the input just fine, but the input doesn’t fire at all when the mouse is over an object inside the frame that can be clicked. (TextBox,ImageButton, etc)

Example of this issue from earlier in the thread

@colbert2677 discovered that the .Active property fixes the CAS issue, making it the perfect solution. Additionally, the trackpad is an exception to the UIS issue, because the new default camera script uses it too, and only goes if GP is false. The old camera script was CAS-based, so you needed the input sink for it to work. Because the new one is UIS (for trackpads, at least) we can use UIS in this case.

Current behavior

This module now behaves exactly as the default scrolling, but smoothed. It is finally exactly what I’ve been trying to achieve this whole time.

When scrolling, the camera doesn’t get affected. Perfect. When there are GuiButtons in the frame, it still scrolls properly, including sinking the input. We did it!

When you call .Enable() on a frame, it will disable .Active on all the frame’s descendants (and future descendants), and store what the property was. When you call .Disable() on the frame, it’ll return all the descendants to their original .Active property. This ensures that CAS behaves properly, and that disabling smoothing will fully return to the original state.


I’m linking it again so you won’t have to scroll all the way back up.


The sensitivity for trackpads appears to be insane in your Lua Learning game, and frames will scroll a ridiculous amount from a tiny trackpad movement. I am using a trackpad on a MacOS if that’s important. I haven’t yet tried Mac trackpad functionality on a scrolling frame using your module.

Edit: I think this is a bug with your game. The module works fine with my trackpad :rofl:

That’s really weird.
And annoying, since I don’t have a trackpad to test with.

Can you DM me more details? Which frame, etc.

Important update!

I discovered some very bad behavior: when hovering over two ScrollingFrames, both would scroll! This is obviously not ideal, as only the top should scroll.

I started doing a bunch of frustrating ancestry ZIndex tree building and sorting to figure out which is above the other.
Then I found PlayerGui:GetGuiObjectsAtPosition(Mouse.X, Mouse.Y). (Wiki)
This function automatically has them sorted, with the top GUI being the first in the array.
Bonus: It’s at mouse position, so I also got to remove all my hovering tracker code since anything in the array is guaranteed to be under the mouse!

Old Behavior:

(Watch the frame in the background)

New Behavior:


(Also, updated OP with example usage on how to automatically smooth every frame with exception support)



Improved drag bar behavior, and added support for multi-axis frames!

Old behavior:
Drag bar jumps to mouse pos, determines canvas position from mouse percent in position, only X or Y bar


(Note how the mouse “slides” along the bar)

New behavior:
Determines canvas position from mouse delta, allows bar for both directions (but MouseWheel is only for Y in that case



1 Like


Added support for ScrollingFrames inside folders!

Also, re-optimized for the new Lua VM!

I forgot that people use folders in their GUIs, so this module would just assume that .Parent was a GuiBase2d object. It now properly utilizes :FindFirstAncestorWhichIsA() in order to handle these cases.
However, the drag bar behaves differently on folder-nested frames. I cannot figure out why, since they run the same code. It still works, but it acts… slippery? It doesn’t stick to the mouse properly. I’ll probably facepalm tomorrow and fix it.




Fixed 2 pretty important bugs!

  1. I think Roblox might have changed the .Active property behavior on Frames because things stopped working for a few people. Fixed it now!

  2. If you called .Disable(), it didn’t :Destroy() the scrollbar buttons, leaking Instances. Fixed this too!
    (Note that you shouldn’t ever really be calling Disable anyway since it automatically disables upon frame deletion, and toggling back and forth during the game is bad practice and wastes resources)



For some reason or another, this seems to cause the camera to zoom again; This used to be fixed, correct?