universal recoil control helper OPEN SOURCE
Key RequiredUniversal

universal recoil control helper OPEN SOURCE

Universal Scripttrashbot76trashbot76 3.5K views 314 executesUpdated Jan 31, 2026
5.0/ 5(1 votes)
10100% Positive
Lua Script•509 lines (14916 chars)
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local TweenService = game:GetService("TweenService")
local Camera = workspace.CurrentCamera
local LocalPlayer = Players.LocalPlayer

local COLORS = {
	darkViolet = Color3.fromRGB(30, 20, 45),
	violet = Color3.fromRGB(95, 65, 140),
	lightViolet = Color3.fromRGB(150, 110, 200),
	accentViolet = Color3.fromRGB(180, 140, 240),
	white = Color3.fromRGB(255, 255, 255),
	textDim = Color3.fromRGB(180, 180, 200),
	success = Color3.fromRGB(120, 220, 170),
	recording = Color3.fromRGB(255, 100, 120),
	selected = Color3.fromRGB(100, 200, 255)
}

local cfg = {
	rec = false,
	act = false,
	patterns = {},
	activePattern = nil,
	selectedPattern = nil,
	currentData = {},
	start = 0,
	idx = 1,
	lastMovement = 0,
	conn1 = nil,
	conn2 = nil,
	lastClick = 0,
	lastClickedPattern = nil
}

local sg = Instance.new("ScreenGui")
sg.Name = "PlayerSettings"
sg.ResetOnSpawn = false
sg.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
sg.IgnoreGuiInset = true
sg.Parent = game:GetService("CoreGui")

local main = Instance.new("Frame")
main.Size = UDim2.new(0, 240, 0, 320)
main.Position = UDim2.new(0.5, -120, 0.5, -160)
main.BackgroundColor3 = COLORS.darkViolet
main.BorderSizePixel = 0
main.Active = true
main.AnchorPoint = Vector2.new(0.5, 0.5)
main.BackgroundTransparency = 1
main.ClipsDescendants = true
main.Parent = sg

local mainGrad = Instance.new("UIGradient")
mainGrad.Color = ColorSequence.new({
	ColorSequenceKeypoint.new(0, COLORS.darkViolet),
	ColorSequenceKeypoint.new(0.5, COLORS.violet),
	ColorSequenceKeypoint.new(1, COLORS.lightViolet)
})
mainGrad.Rotation = 135
mainGrad.Parent = main

local mainStroke = Instance.new("UIStroke")
mainStroke.Thickness = 1
mainStroke.ApplyStrokeMode = Enum.ApplyStrokeMode.Border
mainStroke.Transparency = 1
mainStroke.Parent = main

local strokeGrad = Instance.new("UIGradient")
strokeGrad.Color = ColorSequence.new({
	ColorSequenceKeypoint.new(0, COLORS.violet),
	ColorSequenceKeypoint.new(0.5, COLORS.accentViolet),
	ColorSequenceKeypoint.new(1, COLORS.lightViolet)
})
strokeGrad.Rotation = 45
strokeGrad.Parent = mainStroke

local titleBar = Instance.new("Frame")
titleBar.Size = UDim2.new(1, 0, 0, 28)
titleBar.BackgroundTransparency = 1
titleBar.Parent = main

local title = Instance.new("TextLabel")
title.Size = UDim2.new(1, -16, 1, 0)
title.Position = UDim2.new(0, 8, 0, 0)
title.BackgroundTransparency = 1
title.Text = "recoil helper 1.0"
title.TextColor3 = COLORS.white
title.Font = Enum.Font.GothamBold
title.TextSize = 11
title.TextXAlignment = Enum.TextXAlignment.Left
title.Parent = titleBar

local statusLabel = Instance.new("TextLabel")
statusLabel.Size = UDim2.new(1, -16, 0, 16)
statusLabel.Position = UDim2.new(0, 8, 0, 32)
statusLabel.BackgroundTransparency = 1
statusLabel.Text = "No pattern active"
statusLabel.TextColor3 = COLORS.textDim
statusLabel.Font = Enum.Font.GothamMedium
statusLabel.TextSize = 9
statusLabel.TextXAlignment = Enum.TextXAlignment.Left
statusLabel.Parent = main

local buttonContainer = Instance.new("Frame")
buttonContainer.Size = UDim2.new(1, -16, 0, 24)
buttonContainer.Position = UDim2.new(0, 8, 0, 52)
buttonContainer.BackgroundTransparency = 1
buttonContainer.Parent = main

local recordBtn = Instance.new("TextButton")
recordBtn.Size = UDim2.new(0.33, -4, 1, 0)
recordBtn.Position = UDim2.new(0, 0, 0, 0)
recordBtn.BackgroundColor3 = COLORS.violet
recordBtn.BorderSizePixel = 0
recordBtn.AutoButtonColor = false
recordBtn.Text = "RECORD"
recordBtn.TextColor3 = COLORS.white
recordBtn.Font = Enum.Font.GothamBold
recordBtn.TextSize = 9
recordBtn.Parent = buttonContainer

local recordGrad = Instance.new("UIGradient")
recordGrad.Color = ColorSequence.new({
	ColorSequenceKeypoint.new(0, COLORS.violet),
	ColorSequenceKeypoint.new(1, COLORS.lightViolet)
})
recordGrad.Rotation = 90
recordGrad.Parent = recordBtn

local recordStroke = Instance.new("UIStroke")
recordStroke.Thickness = 1
recordStroke.ApplyStrokeMode = Enum.ApplyStrokeMode.Border
recordStroke.Transparency = 0.3
recordStroke.Color = COLORS.accentViolet
recordStroke.Parent = recordBtn

local saveBtn = Instance.new("TextButton")
saveBtn.Size = UDim2.new(0.33, -4, 1, 0)
saveBtn.Position = UDim2.new(0.33, 2, 0, 0)
saveBtn.BackgroundColor3 = COLORS.violet
saveBtn.BorderSizePixel = 0
saveBtn.AutoButtonColor = false
saveBtn.Text = "SAVE"
saveBtn.TextColor3 = COLORS.white
saveBtn.Font = Enum.Font.GothamBold
saveBtn.TextSize = 9
saveBtn.Parent = buttonContainer

local saveGrad = Instance.new("UIGradient")
saveGrad.Color = ColorSequence.new({
	ColorSequenceKeypoint.new(0, COLORS.violet),
	ColorSequenceKeypoint.new(1, COLORS.lightViolet)
})
saveGrad.Rotation = 90
saveGrad.Parent = saveBtn

local saveStroke = Instance.new("UIStroke")
saveStroke.Thickness = 1
saveStroke.ApplyStrokeMode = Enum.ApplyStrokeMode.Border
saveStroke.Transparency = 0.3
saveStroke.Color = COLORS.accentViolet
saveStroke.Parent = saveBtn

local deleteBtn = Instance.new("TextButton")
deleteBtn.Size = UDim2.new(0.33, -4, 1, 0)
deleteBtn.Position = UDim2.new(0.66, 4, 0, 0)
deleteBtn.BackgroundColor3 = COLORS.violet
deleteBtn.BorderSizePixel = 0
deleteBtn.AutoButtonColor = false
deleteBtn.Text = "DELETE"
deleteBtn.TextColor3 = COLORS.white
deleteBtn.Font = Enum.Font.GothamBold
deleteBtn.TextSize = 9
deleteBtn.Parent = buttonContainer

local deleteGrad = Instance.new("UIGradient")
deleteGrad.Color = ColorSequence.new({
	ColorSequenceKeypoint.new(0, COLORS.violet),
	ColorSequenceKeypoint.new(1, COLORS.lightViolet)
})
deleteGrad.Rotation = 90
deleteGrad.Parent = deleteBtn

local deleteStroke = Instance.new("UIStroke")
deleteStroke.Thickness = 1
deleteStroke.ApplyStrokeMode = Enum.ApplyStrokeMode.Border
deleteStroke.Transparency = 0.3
deleteStroke.Color = COLORS.accentViolet
deleteStroke.Parent = deleteBtn

local listLabel = Instance.new("TextLabel")
listLabel.Size = UDim2.new(1, -16, 0, 16)
listLabel.Position = UDim2.new(0, 8, 0, 84)
listLabel.BackgroundTransparency = 1
listLabel.Text = "PATTERNS (Double tap = Equip, Single tap = Select)"
listLabel.TextColor3 = COLORS.textDim
listLabel.Font = Enum.Font.GothamMedium
listLabel.TextSize = 8
listLabel.TextXAlignment = Enum.TextXAlignment.Left
listLabel.Parent = main

local scrollContainer = Instance.new("Frame")
scrollContainer.Size = UDim2.new(1, 0, 1, -108)
scrollContainer.Position = UDim2.new(0, 0, 0, 108)
scrollContainer.BackgroundTransparency = 1
scrollContainer.ClipsDescendants = true
scrollContainer.Parent = main

local scroll = Instance.new("ScrollingFrame")
scroll.Size = UDim2.new(1, 0, 1, 0)
scroll.CanvasSize = UDim2.new(0, 0, 0, 0)
scroll.BackgroundTransparency = 1
scroll.BorderSizePixel = 0
scroll.ScrollBarThickness = 4
scroll.ScrollBarImageColor3 = COLORS.accentViolet
scroll.ScrollingDirection = Enum.ScrollingDirection.Y
scroll.AutomaticCanvasSize = Enum.AutomaticSize.Y
scroll.ScrollBarImageTransparency = 0.5
scroll.Parent = scrollContainer

local listContent = Instance.new("Frame")
listContent.Size = UDim2.new(1, -16, 1, 0)
listContent.Position = UDim2.new(0, 8, 0, 0)
listContent.BackgroundTransparency = 1
listContent.AutomaticSize = Enum.AutomaticSize.Y
listContent.Parent = scroll

local listLayout = Instance.new("UIListLayout")
listLayout.Padding = UDim.new(0, 4)
listLayout.SortOrder = Enum.SortOrder.LayoutOrder
listLayout.Parent = listContent

local dragging, dragStart, startPos = false, nil, nil

titleBar.InputBegan:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseButton1 then
		dragging = true
		dragStart = input.Position
		startPos = main.Position
	end
end)

UserInputService.InputChanged:Connect(function(input)
	if dragging and input.UserInputType == Enum.UserInputType.MouseMovement then
		local delta = input.Position - dragStart
		main.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y)
	end
end)

UserInputService.InputEnded:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseButton1 then
		dragging = false
	end
end)

task.spawn(function()
	main.Size = UDim2.new(0, 0, 0, 0)
	TweenService:Create(main, TweenInfo.new(0.3, Enum.EasingStyle.Quint, Enum.EasingDirection.Out), {
		Size = UDim2.new(0, 240, 0, 320),
		BackgroundTransparency = 0
	}):Play()
	TweenService:Create(mainStroke, TweenInfo.new(0.3, Enum.EasingStyle.Quint, Enum.EasingDirection.Out), {
		Transparency = 0
	}):Play()
end)

local function getAngles()
	local lv = Camera.CFrame.LookVector
	local pitch = math.asin(-lv.Y)
	local yaw = math.atan2(lv.X, lv.Z)
	return pitch, yaw
end

local function normalize(angle)
	while angle > math.pi do angle = angle - 2 * math.pi end
	while angle < -math.pi do angle = angle + 2 * math.pi end
	return angle
end

local function updateList()
	for _, child in ipairs(listContent:GetChildren()) do
		if child:IsA("Frame") then child:Destroy() end
	end
	
	for i, pattern in ipairs(cfg.patterns) do
		local item = Instance.new("Frame")
		item.Size = UDim2.new(1, 0, 0, 28)
		item.BackgroundColor3 = COLORS.violet
		item.BorderSizePixel = 0
		item.LayoutOrder = i
		item.Parent = listContent
		
		local itemGrad = Instance.new("UIGradient")
		itemGrad.Color = ColorSequence.new({
			ColorSequenceKeypoint.new(0, COLORS.violet),
			ColorSequenceKeypoint.new(1, COLORS.lightViolet)
		})
		itemGrad.Rotation = 90
		itemGrad.Parent = item
		
		local itemStroke = Instance.new("UIStroke")
		itemStroke.Thickness = 1
		itemStroke.ApplyStrokeMode = Enum.ApplyStrokeMode.Border
		itemStroke.Transparency = 0.5
		itemStroke.Color = COLORS.accentViolet
		itemStroke.Parent = item
		
		if cfg.activePattern == pattern then
			itemStroke.Color = COLORS.success
			itemStroke.Transparency = 0
		elseif cfg.selectedPattern == pattern then
			itemStroke.Color = COLORS.selected
			itemStroke.Transparency = 0
		end
		
		local label = Instance.new("TextLabel")
		label.Size = UDim2.new(1, -16, 1, 0)
		label.Position = UDim2.new(0, 8, 0, 0)
		label.BackgroundTransparency = 1
		label.Text = pattern.name .. " (" .. #pattern.data .. " frames)"
		label.TextColor3 = COLORS.white
		label.Font = Enum.Font.GothamMedium
		label.TextSize = 9
		label.TextXAlignment = Enum.TextXAlignment.Left
		label.Parent = item
		
		local btn = Instance.new("TextButton")
		btn.Size = UDim2.new(1, 0, 1, 0)
		btn.BackgroundTransparency = 1
		btn.Text = ""
		btn.Parent = item
		
		btn.MouseButton1Click:Connect(function()
			local now = tick()
			if cfg.lastClickedPattern == pattern and (now - cfg.lastClick) < 0.3 then
				cfg.activePattern = pattern
				statusLabel.Text = "Active: " .. pattern.name
				statusLabel.TextColor3 = COLORS.success
			else
				cfg.selectedPattern = pattern
			end
			cfg.lastClick = now
			cfg.lastClickedPattern = pattern
			updateList()
		end)
	end
end

local function startRec()
	if cfg.rec then return end
	
	cfg.rec = true
	cfg.currentData = {}
	cfg.start = tick()
	cfg.lastMovement = tick()
	
	local startPitch, startYaw = getAngles()
	local lastPitch, lastYaw = startPitch, startYaw
	
	recordBtn.Text = "REC..."
	recordBtn.BackgroundColor3 = COLORS.recording
	recordGrad.Color = ColorSequence.new(COLORS.recording)
	statusLabel.Text = "Recording... Move mouse down while shooting"
	statusLabel.TextColor3 = COLORS.recording
	
	if cfg.conn2 then cfg.conn2:Disconnect() end
	
	cfg.conn2 = RunService.Heartbeat:Connect(function()
		local elapsed = tick() - cfg.start
		local timeSinceMovement = tick() - cfg.lastMovement
		
		if elapsed >= 4 or timeSinceMovement >= 3 then
			cfg.conn2:Disconnect()
			cfg.conn2 = nil
			cfg.rec = false
			recordBtn.Text = "RECORD"
			recordBtn.BackgroundColor3 = COLORS.violet
			recordGrad.Color = ColorSequence.new({
				ColorSequenceKeypoint.new(0, COLORS.violet),
				ColorSequenceKeypoint.new(1, COLORS.lightViolet)
			})
			if #cfg.currentData > 5 then
				statusLabel.Text = "Pattern recorded (" .. #cfg.currentData .. " frames) - Click SAVE"
				statusLabel.TextColor3 = COLORS.success
			else
				statusLabel.Text = "Recording failed - too short"
				statusLabel.TextColor3 = COLORS.recording
				cfg.currentData = {}
			end
			return
		end
		
		local p, y = getAngles()
		
		local dp = p - lastPitch
		local dy = normalize(y - lastYaw)
		
		if math.abs(dp) > 0.0001 or math.abs(dy) > 0.0001 then
			cfg.lastMovement = tick()
			table.insert(cfg.currentData, {dp, dy})
		end
		
		lastPitch, lastYaw = p, y
	end)
end

local function savePattern()
	if #cfg.currentData == 0 then
		statusLabel.Text = "No pattern to save"
		statusLabel.TextColor3 = COLORS.recording
		return
	end
	
	local compensationData = {}
	for _, frame in ipairs(cfg.currentData) do
		table.insert(compensationData, {-frame[1] * 0.95, -frame[2] * 0.95})
	end
	
	local patternName = "Pattern " .. (#cfg.patterns + 1)
	table.insert(cfg.patterns, {
		name = patternName,
		data = compensationData
	})
	
	cfg.currentData = {}
	statusLabel.Text = "Saved: " .. patternName
	statusLabel.TextColor3 = COLORS.success
	updateList()
end

local function deletePattern()
	if not cfg.selectedPattern then
		statusLabel.Text = "No pattern selected"
		statusLabel.TextColor3 = COLORS.recording
		return
	end
	
	for i, pattern in ipairs(cfg.patterns) do
		if pattern == cfg.selectedPattern then
			table.remove(cfg.patterns, i)
			if cfg.activePattern == cfg.selectedPattern then
				cfg.activePattern = nil
				statusLabel.Text = "Pattern deleted"
			end
			cfg.selectedPattern = nil
			updateList()
			return
		end
	end
end

local function apply()
	if not cfg.activePattern or not cfg.act then return end
	
	local data = cfg.activePattern.data
	if #data == 0 then return end
	
	local f = data[cfg.idx]
	if not f then
		cfg.idx = 1
		f = data[1]
		if not f then return end
	end
	
	local p, y = getAngles()
	local np = math.clamp(p + f[1], -math.pi/2 + 0.01, math.pi/2 - 0.01)
	local ny = normalize(y + f[2])
	
	local lv = Vector3.new(
		math.cos(np) * math.sin(ny),
		-math.sin(np),
		math.cos(np) * math.cos(ny)
	)
	
	Camera.CFrame = CFrame.new(Camera.CFrame.Position, Camera.CFrame.Position + lv)
	
	cfg.idx = cfg.idx + 1
	if cfg.idx > #data then cfg.idx = 1 end
end

recordBtn.MouseButton1Click:Connect(function()
	if not cfg.rec then startRec() end
end)

saveBtn.MouseButton1Click:Connect(savePattern)
deleteBtn.MouseButton1Click:Connect(deletePattern)

UserInputService.InputBegan:Connect(function(input, gp)
	if gp then return end
	
	if input.UserInputType == Enum.UserInputType.MouseButton1 and cfg.activePattern and not cfg.rec then
		cfg.act = true
		cfg.idx = 1
		
		if cfg.conn1 then cfg.conn1:Disconnect() end
		cfg.conn1 = RunService.Heartbeat:Connect(apply)
	end
end)

UserInputService.InputEnded:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseButton1 then
		cfg.act = false
		if cfg.conn1 then cfg.conn1:Disconnect() cfg.conn1 = nil end
		cfg.idx = 1
	end
end)

updateList()

Features & Information

basic script that controls your recoil while youre shooting as good as it can HOW TO USE record recoil join a game click record shoot a wall and let the gun go up naturally wait 4 seconds then click save save pattern double click pattern 1 or 2 etc green border means its active hold left mouse while shooting script pulls aim down recoil is controlled have fun
#free#universal#recoil#recoil controller#recoil helper

Community Comments (0)

No comments yet for this script.

More Scripts for Universal Scripts