Simple Interface Shaker Module

(Use this) New Module: https://create.roblox.com/store/asset/90939572208441/
Legacy Module: https://create.roblox.com/store/asset/14144240995/


If you find any bugs, please make a reply about them here.

Finally, after time and time, I have finally finished the complete revamp of this module.
How it works is very simple, if you are familiar with the CameraShaker Module


How to use this???

Oh, simpler than you think.
Let’s create a script where once you click a TextButton, the button will shake a little

local Button = script.Parent:WaitForChild("TextButton")
local InterfaceShaker = require(game:GetService("ReplicatedStorage"):WaitForChild("InterfaceShaker"))
local function OnClick()
	InterfaceShaker.ShakeOnce(Button, 10, 0, 0, 0.2)
end

Button.MouseButton1Click:Connect(OnClick)
-- InterfaceShaker.ShakeOnce(element, magnitude, duration, fadeIn, fadeOut)

This is probably everything you need to know.
However, you can also make the module only rotate the element:

local function OnClick()
	InterfaceShaker.ApplyPosition = false
	InterfaceShaker.ShakeOnce(Button, 10, 0.1, 0, 0.4)
end

Or, the opposite, only make it Position stuff.

local function OnClick()
	InterfaceShaker.ApplyRotation = false
	InterfaceShaker.ShakeOnce(Button, 10, 0.1, 0, 0.4)
end

You can view the source code here:

local module = {
	["Threads"] = {},
	["StartPositions"] = {},
	["StartRotations"] = {},
	["CancelEvents"] = {},
	["ApplyPosition"] = true,
	["ApplyRotation"] = true,
}

local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")
local RNG = Random.new()

function module.ShakeOnce(element : GuiObject, magnitude, duration, fadeIn, fadeOut)
	if not module.ApplyPosition and not module.ApplyRotation then
		return
	end
	local ExistingThread = module.Threads[element]
	if ExistingThread then
		module.CancelEvents[element]:Fire()
		task.cancel(module.Threads[element])
		module.Threads[element] = nil
	end
	
	local PreviousPosition = module.StartPositions[element] or element.Position
	local PreviousRotation = module.StartRotations[element] or element.Rotation
	local CancelBindable = Instance.new("BindableEvent")
	local OnCancel = CancelBindable.Event
	if not module.StartPositions[element] then
		module.StartPositions[element] = PreviousPosition
	end
	module.StartRotations[element] = PreviousRotation
	module.CancelEvents[element] = CancelBindable
	module.Threads[element] = task.spawn(function()
		local _v1 = (magnitude/800)
		local _v2 = (magnitude)
		local _r2 = {
			multiplier = Instance.new("NumberValue"), -- markipliers
			rotation = Instance.new("NumberValue"),
			position = Instance.new("Vector3Value"),
		}
		
		_r2.multiplier.Value = 0
		
		local Connection : RBXScriptConnection
		local ConnectionCancel : RBXScriptConnection
		local Main = task.spawn(function()
			local lastValue = Vector3.zero
			Connection = RunService.RenderStepped:Connect(function(delta)
				local rangeX = RNG:NextNumber(-_v1, _v1)
				local rangeY = RNG:NextNumber(-_v1, _v1)
				local rangeR = RNG:NextNumber(-_v2, _v2)
				_r2.position.Value = Vector3.new(
					rangeX,
					rangeY,
					0
				)
				if module.ApplyPosition then
					element.Position = PreviousPosition + UDim2.fromScale(
						(_r2.position.Value.X) * _r2.multiplier.Value,
						(_r2.position.Value.Y) * _r2.multiplier.Value
					)
				end
				_r2.rotation.Value = rangeR
				if module.ApplyRotation then
					element.Rotation = PreviousRotation + _r2.rotation.Value * _r2.multiplier.Value
				end
			end)
		end)
		
		local v = task.spawn(function()
			TweenService:Create(
				_r2.multiplier,
				TweenInfo.new(fadeIn, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut),
				{Value = 1}
			):Play()
			task.wait(fadeIn)
			_r2.multiplier.Value = 1
			task.wait(duration)
			TweenService:Create(
				_r2.multiplier,
				TweenInfo.new(fadeOut, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut),
				{Value = 0}
			):Play()
			task.wait(fadeOut)
			_r2.multiplier.Value = 0
			CancelBindable:Fire()
		end)
		
		ConnectionCancel = OnCancel:Connect(function()
			task.cancel(Main)
			task.cancel(v)
			Connection:Disconnect()
			ConnectionCancel:Disconnect()
			CancelBindable:Destroy()
			_r2.rotation:Destroy()
			_r2.position:Destroy()
			_r2.multiplier:Destroy()
			_r2 = {}
			
			module.Threads[element] = nil
		end)
	end)
end

return module

Thanks, bye!!!

58 Likes

What would be nicer is if you stored the original position/orientation in the module itself. Nice module though.

11 Likes

Would check this out when I get access to Studio, but thanks for sharing!

3 Likes

Really thanks for all the likes and purchases :smiley:

4 Likes

the game keeps lagging every time the script is played

2 Likes

The lag issue most likely happens because the code keeps creating a new renderstepped event every time you use the shake function, without properly ending the previous ones. To fix this, you can disconnect the event either when it stops or before calling it again.

Note where the renderConnection variable is being disconnected

local renderConnection = nil
function module:ShakeOnce(element, intensity, fadeOutTime, delayTime)
	spawn(function()
		if renderConnection then
			renderConnection:Disconnect()
		end
		local Stopped = false
		local ReferenceIntensityValue = Instance.new('NumberValue', script)
		ReferenceIntensityValue.Value = intensity

		--// Basics \\--

		local OriginalPositionAttribute = element:SetAttribute("OriginalPosition", element.Position)
		local OriginalRotationAttribute = element:SetAttribute("OriginalRotation", element.Rotation)

		local OffsetConvert = 700
		local RotationConvert = intensity/1000

		renderConnection = RunService.RenderStepped:Connect(function(dt)
			if Stopped == false then
				intensity = ReferenceIntensityValue.Value 
				local OriginalPosition = element:GetAttribute("OriginalPosition")

				element.Position = OriginalPosition + UDim2.new(
					math.random(-intensity, intensity)/OffsetConvert,
					0,
					math.random(-intensity, intensity)/OffsetConvert,
					0
				)

			end
		end)

		spawn(function()
			while wait() do
				if Stopped == false then
					element.Rotation = math.random(-intensity, intensity)/2
				end
			end
		end)

		wait(delayTime)

		local CalmTween = TweenService:Create(ReferenceIntensityValue, TweenInfo.new(fadeOutTime, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut, 0, false, 0), {Value = 0})
		CalmTween:Play()
		CalmTween.Completed:Wait()

		Stopped = true
		if renderConnection then
			renderConnection:Disconnect()
		end
		element.Position =  element:GetAttribute("OriginalPosition")
		element.Rotation = element:GetAttribute("OriginalRotation")
		task.wait()
		element:SetAttribute("OriginalPosition", nil)
		element:SetAttribute("OriginalRotation", nil)
		
		ReferenceIntensityValue:Destroy()
	end)
end
3 Likes

image
image

UPDATE

Huge thanks to @WlZ_ONE for letting me know about the lag thats being caused when the module is running :+1:

Hey your latest fix made it so if you did something like

guiShaker:ShakeOnce(YouDied, 20, 1.2, 0)
guiShaker:ShakeOnce(DeathText, 20, respawnTime + 1, 0)

it wouldnt work as intended because RunService.RenderStepped would get cancelled if the function got called, so i made this

local module = {}

local RunService = game:GetService('RunService')
local TweenService = game:GetService('TweenService')

local ShakeOnceConnections = {}
local ShakeConnections = {}

function module:ShakeOnce(element, intensity, fadeOutTime, delayTime) -- Smoothing
	task.spawn(function()
		local Stopped = false
		local ReferenceIntensityValue = Instance.new('NumberValue', script)
		local tablePos = ShakeOnceConnections[#ShakeOnceConnections + 1]
		ReferenceIntensityValue.Value = intensity

		--// Basics \\--

		local OriginalPositionAttribute = element:SetAttribute("OriginalPosition", element.Position)
		local OriginalRotationAttribute = element:SetAttribute("OriginalRotation", element.Rotation)

		local OffsetConvert = 700
		local RotationConvert = intensity/1000

		tablePos = RunService.RenderStepped:Connect(function(dt)
			if Stopped == false then
				intensity = ReferenceIntensityValue.Value 
				local OriginalPosition = element:GetAttribute("OriginalPosition")

				element.Position = OriginalPosition + UDim2.new(
					math.random(-intensity, intensity)/OffsetConvert,
					0,
					math.random(-intensity, intensity)/OffsetConvert,
					0
				)

			end
		end)

		task.spawn(function()
			while task.wait() do
				if Stopped == false then
					element.Rotation = math.random(-intensity, intensity)/2
				end
			end
		end)

		task.wait(delayTime)

		local CalmTween = TweenService:Create(ReferenceIntensityValue, TweenInfo.new(fadeOutTime, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut, 0, false, 0), {Value = 0})
		CalmTween:Play()
		CalmTween.Completed:Wait()

		Stopped = true
		
		element.Position =  element:GetAttribute("OriginalPosition")
		element.Rotation = element:GetAttribute("OriginalRotation")
		task.wait()
		element:SetAttribute("OriginalPosition", nil)
		element:SetAttribute("OriginalRotation", nil)
		tablePos = nil
		ReferenceIntensityValue:Destroy()
	end)
	
end

function module:Shake(element, intensity, length)
	task.spawn(function()
		local Stopped = false
		local tablePos = ShakeOnceConnections[#ShakeOnceConnections + 1]

		--// Basics \\--

		local OriginalPositionAttribute = element:SetAttribute("OriginalPosition", element.Position)
		local OriginalRotationAttribute = element:SetAttribute("OriginalRotation", element.Rotation)

		local OffsetConvert = 700
		local RotationConvert = intensity/1000
		
		tablePos = RunService.RenderStepped:Connect(function(dt)
			if Stopped == false then
				local OriginalPosition = element:GetAttribute("OriginalPosition")

				element.Position = OriginalPosition + UDim2.new(
					math.random(-intensity, intensity)/OffsetConvert,
					0,
					math.random(-intensity, intensity)/OffsetConvert,
					0
				)

			end
		end)

		task.spawn(function()
			while task.wait() do
				if Stopped == false then
					element.Rotation = math.random(-intensity, intensity)/2
				end
			end
		end)

		task.wait(length)
		
		Stopped = true
		intensity = 0
		
		element.Position =  element:GetAttribute("OriginalPosition")
		element.Rotation = element:GetAttribute("OriginalRotation")
		task.wait()
		tablePos = nil
		element:SetAttribute("OriginalPosition", nil)
		element:SetAttribute("OriginalRotation", nil)
	end)
end

return module
2 Likes

On an unrelated note, this is a very cool module i like it very much, heres a basic deathscreen i made out of it

5 Likes

i like your avatar :smile: its very prutty good

Hi, I used the “shakeOnce” function but I got an error. I assume its because the attribute can’t take the position number??

Here is what I did

guiShaker.ShakeOnce(playerBarHealthLeft, 4, 0.4, 0)

It errors:
“Attempted to index number with position”

What is playerBarHealthLeft? The first argument passed MUST be a UI Object (Frame for example)

:heart:


It’s a frame indeed. Idk why it broke

1 Like

Ngl yours its actually cooler but i actually used it for a game over screen aswell LOL since i was using a pretty unpolished way to do shaking but then found out this module, pretty well made both your game over screen and this module ngl

In case you wanna see mine, here it is

External Media
2 Likes

Awesome!
I’m developing a new version, which is almost ready, just requires bug fixes

It will contain more features than the current one!

Hey! I made a version of your module that supports 3D Instances. Can i have your permission to post it here?

1 Like

Sure thing!


Did you fix it, or did it just go away? I got this issue right now

edit: make sure to use a colon, and not dot notation.