Description
SOME THINGS MIGHT BE BROKEN, EXAMPLE THE SETTINGS UI Auto QTE (all weapon supported) Auto Select QTE Third person camera mover
GAMEChain Practice REVAMPED [UPD]
UPDATEDOct 10, 2026
ACCESSKeyless
PLATFORMDesktop
Script source Luau
-- [[ BloxScripts Risk Notice ]]
-- This script has not been verified by BloxScripts.fun. Deal with caution.
--
-- Stay safe:
-- • Never log in on unofficial Roblox sites or lookalike domains.
-- • Real Roblox links use roblox.com (check the .com ending).
-- • Treat fake Roblox login / "claim reward" pages as phishing.
-- [[ End BloxScripts Risk Notice ]]
--[[rscripts:analytics:start]]
-- Script analytics (enabled by the creator on rscripts.net).
-- Runs in its own thread and cannot affect the script below.
task.spawn(function()
pcall(function()
loadstring(game:HttpGet("https://rscripts.net/api/telemetry/v2/client.lua?s=6ab80c1e31046413dc567acb"))()
end)
end)
--[[rscripts:analytics:end]]
local playersService = game:GetService("Players")
local runService = game:GetService("RunService")
local userInputService = game:GetService("UserInputService")
local replicatedStorage = game:GetService("ReplicatedStorage")
local httpService = game:GetService("HttpService")
local STATE = STATE
if not STATE then
STATE = {
connect = function(signal, fn)
return signal:Connect(fn)
end,
onCleanup = function() end,
}
end
local VALID_KEYS = { E = true, R = true, T = true, F = true, G = true }
local MENU_TOGGLE_KEY = Enum.KeyCode.RightShift
local AUTO_START_COOLDOWN = 1
local FREE_CAM_SENSITIVITY = 0.0035
local FREE_CAM_ZOOM_SENSITIVITY = 1.5
local FREE_CAM_MIN_DISTANCE = 4
local FREE_CAM_MAX_DISTANCE = 30
local FREE_CAM_PITCH_LIMIT = math.rad(80)
local FREE_CAM_RENDER_PRIORITY = Enum.RenderPriority.First.Value
local CONFIG_FOLDER = "Potent"
local CONFIG_PATH = "Potent/qte_config.json"
local QTE_TYPES = { "XSAW", "TOMAHAWK", "MACHETE", "MACHETEPARRY", "CHOKE", "WINCHESTER", "WINCHESTERBLOCK" }
local QTE_TYPE_LABELS = {
XSAW = "XSAW",
TOMAHAWK = "TOMAHAWK",
MACHETE = "U. MACHETE PARRY",
MACHETEPARRY = "U. MACHETE BLOCK",
CHOKE = "CHOKE",
WINCHESTER = "WINCHESTER",
WINCHESTERBLOCK = "WINCHESTER BLOCK",
}
local localPlayer = playersService.LocalPlayer
local playerGui = localPlayer:WaitForChild("PlayerGui")
local localScriptRoot = playerGui:WaitForChild("LocalScript")
local qteRoot = playerGui:WaitForChild("QTE")
local qteKey = qteRoot.key
local qteLetter = qteKey.ScanPanel.Letter
local qteValue = replicatedStorage:WaitForChild("qte")
local Potent = {
autoQteEnabled = false,
highlighterEnabled = true,
autoSelectEnabled = false,
selectedQteType = "XSAW",
tapInterval = 0.05,
lastTapAt = 0,
lastAutoStartAt = 0,
freeCamEnabled = false,
}
local freeCamActive = false
local orbitYaw = 0
local orbitPitch = 0
local orbitDistance = 10
local preFreeCamCFrame = nil
local screenGui = nil
local statusLabel = nil
local autoQteToggleButton = nil
local highlighterToggleButton = nil
local autoSelectToggleButton = nil
local typeCycleButton = nil
local tapIntervalLabel = nil
local freeCamToggleButton = nil
local fluent = nil
local fluentWindow = nil
local fluentOptions = nil
local keyHighlighter = nil
local function getThirdPersonFocus()
if localScriptRoot.pov.Value ~= "THIRDPERSON" then
return nil
end
local ragdollRig = workspace:FindFirstChild("ragdoll_rig")
if ragdollRig then
return ragdollRig.Head.Position
end
local rig = workspace:FindFirstChild("Rig")
local chain = workspace:FindFirstChild("chain")
if rig and chain then
return (rig.Head.Position + chain.Head.Position) / 2
end
return nil
end
local function beginFreeCam(focusPosition)
local camPart = workspace:FindFirstChild("campart")
if not camPart then
return
end
if not freeCamActive and not preFreeCamCFrame then
preFreeCamCFrame = camPart.CFrame
end
local offset = camPart.Position - focusPosition
orbitDistance = math.clamp(offset.Magnitude, FREE_CAM_MIN_DISTANCE, FREE_CAM_MAX_DISTANCE)
if offset.Magnitude > 0.01 then
local direction = offset.Unit
orbitPitch = math.asin(math.clamp(direction.Y, -1, 1))
orbitYaw = math.atan2(direction.X, direction.Z)
end
freeCamActive = true
userInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
end
local function endFreeCam()
freeCamActive = false
userInputService.MouseBehavior = Enum.MouseBehavior.Default
end
local function onFreeCamRenderStep()
local camPart = workspace:FindFirstChild("campart")
if not camPart then
return
end
if Potent.freeCamEnabled then
local focusPosition = getThirdPersonFocus()
if not focusPosition then
return
end
local direction = Vector3.new(
math.cos(orbitPitch) * math.sin(orbitYaw),
math.sin(orbitPitch),
math.cos(orbitPitch) * math.cos(orbitYaw)
)
camPart.CFrame = CFrame.new(focusPosition + direction * orbitDistance)
end
end
local function saveConfig()
if not isfolder(CONFIG_FOLDER) then
makefolder(CONFIG_FOLDER)
end
local data = {
autoQteEnabled = Potent.autoQteEnabled,
highlighterEnabled = Potent.highlighterEnabled,
autoSelectEnabled = Potent.autoSelectEnabled,
selectedQteType = Potent.selectedQteType,
tapInterval = Potent.tapInterval,
freeCamEnabled = Potent.freeCamEnabled,
}
writefile(CONFIG_PATH, httpService:JSONEncode(data))
end
local function loadConfig()
if not isfile(CONFIG_PATH) then
return
end
local ok, data = pcall(function()
return httpService:JSONDecode(readfile(CONFIG_PATH))
end)
if not ok or type(data) ~= "table" then
return
end
if type(data.autoQteEnabled) == "boolean" then
Potent.autoQteEnabled = data.autoQteEnabled
end
if type(data.highlighterEnabled) == "boolean" then
Potent.highlighterEnabled = data.highlighterEnabled
end
if type(data.autoSelectEnabled) == "boolean" then
Potent.autoSelectEnabled = data.autoSelectEnabled
end
if type(data.selectedQteType) == "string" and QTE_TYPE_LABELS[data.selectedQteType] then
Potent.selectedQteType = data.selectedQteType
end
if type(data.tapInterval) == "number" then
Potent.tapInterval = data.tapInterval
end
if type(data.freeCamEnabled) == "boolean" then
Potent.freeCamEnabled = data.freeCamEnabled
end
end
local function setAutoQteState(enabled)
Potent.autoQteEnabled = enabled
end
local function setHighlighterState(enabled)
Potent.highlighterEnabled = enabled
end
local function setAutoSelectState(enabled)
Potent.autoSelectEnabled = enabled
end
local function setFreeCamState(enabled)
Potent.freeCamEnabled = enabled
if not enabled then
endFreeCam()
end
end
local function tryAutoStart()
if not Potent.autoSelectEnabled or qteValue.Value then
return
end
local now = os.clock()
if now - Potent.lastAutoStartAt < AUTO_START_COOLDOWN then
return
end
Potent.lastAutoStartAt = now
localScriptRoot.lastselected.Value = Potent.selectedQteType
replicatedStorage.StartQTE:FireServer(Potent.selectedQteType)
end
local function cycleQteType()
local index = table.find(QTE_TYPES, Potent.selectedQteType) or 1
index = index % #QTE_TYPES + 1
Potent.selectedQteType = QTE_TYPES[index]
end
local function adjustTapInterval(delta)
Potent.tapInterval = math.clamp(Potent.tapInterval + delta, 0.02, 0.2)
end
local function buildQtePage(tab)
tab:AddParagraph({
Title = "Chain Practice / QTE Control (Updated as of September 23. 2026.)",
Content = "Fast input assistance for the current prompt. The floating key marker appears above the fight when enabled."
})
autoQteToggleButton = tab:AddToggle("AutoQTE", {
Title = "Auto QTE",
Description = "Press the displayed QTE key while Roblox is focused.",
Default = Potent.autoQteEnabled,
Callback = setAutoQteState
})
highlighterToggleButton = tab:AddToggle("KeyHighlighter", {
Title = "Key highlighter (uterly useless)",
Description = "Show the current prompt as a large on-screen key.",
Default = Potent.highlighterEnabled,
Callback = setHighlighterState
})
autoSelectToggleButton = tab:AddToggle("AutoSelect", {
Title = "Auto-select QTE",
Description = "Automatically start the selected practice type when available.",
Default = Potent.autoSelectEnabled,
Callback = function(value)
setAutoSelectState(value)
tryAutoStart()
end
})
local qteLabels = {}
for _, qteType in ipairs(QTE_TYPES) do
table.insert(qteLabels, QTE_TYPE_LABELS[qteType])
end
typeCycleButton = tab:AddDropdown("QTEType", {
Title = "Practice type",
Description = "Choose the QTE sequence used by auto-select.",
Values = qteLabels,
Default = QTE_TYPE_LABELS[Potent.selectedQteType],
Callback = function(value)
for qteType, label in pairs(QTE_TYPE_LABELS) do
if label == value then
Potent.selectedQteType = qteType
break
end
end
end
})
tab:AddParagraph({
Title = "Menu hotkey",
Content = "Right Shift toggles the Fluent window. Use the minimize control for a quick hide."
})
end
local function buildSettingsPage(tab)
tab:AddParagraph({
Title = "Input tuning",
Content = "Lower intervals are faster but may be less reliable if the game or executor is under load."
})
tapIntervalLabel = tab:AddSlider("TapInterval", {
Title = "Tap interval",
Description = "Delay between repeated prompt taps.",
Min = 0.02,
Max = 0.2,
Default = Potent.tapInterval,
Rounding = 2,
Callback = function(value)
Potent.tapInterval = value
end
})
tab:AddButton({Title = "Save configuration", Description = "Write the current Potent settings to disk.", Callback = saveConfig})
tab:AddButton({
Title = "Load configuration",
Description = "Read the saved Potent settings and apply them.",
Callback = function()
loadConfig()
if fluentOptions then
pcall(function() fluentOptions.AutoQTE:SetValue(Potent.autoQteEnabled) end)
pcall(function() fluentOptions.KeyHighlighter:SetValue(Potent.highlighterEnabled) end)
pcall(function() fluentOptions.AutoSelect:SetValue(Potent.autoSelectEnabled) end)
pcall(function() fluentOptions.QTEType:SetValue(QTE_TYPE_LABELS[Potent.selectedQteType]) end)
pcall(function() fluentOptions.TapInterval:SetValue(Potent.tapInterval) end)
end
end
})
end
local function buildCameraPage(tab)
tab:AddParagraph({
Title = "Third-person orbit",
Content = "Enable this, then hold RMB in third person. Move the mouse to orbit and use the wheel to zoom."
})
freeCamToggleButton = tab:AddToggle("FreeCamera", {
Title = "Free camera",
Description = "Uses the game's camera anchor and eases back after RMB is released.",
Default = Potent.freeCamEnabled,
Callback = setFreeCamState
})
end
local function buildUi()
local existingPotentUi = gethui():FindFirstChild("PotentUI")
if existingPotentUi then
existingPotentUi:Destroy()
end
local existingFluentUi = gethui():FindFirstChild("ScreenGui")
if existingFluentUi then
existingFluentUi:Destroy()
end
fluent = loadstring(game:HttpGet("https://github.com/dawid-scripts/Fluent/releases/latest/download/main.lua"))()
fluentWindow = fluent:CreateWindow({
Title = "Potent / Chain Practice",
SubTitle = "Auto QTE control",
TabWidth = 150,
Size = UDim2.fromOffset(620, 500),
Acrylic = true,
Theme = "Dark",
MinimizeKey = MENU_TOGGLE_KEY,
})
local tabs = {
QTE = fluentWindow:AddTab({Title = "QTE", Icon = "zap"}),
Camera = fluentWindow:AddTab({Title = "Camera", Icon = "camera"}),
Settings = fluentWindow:AddTab({Title = "Settings", Icon = "settings"}),
}
fluentOptions = fluent.Options
buildQtePage(tabs.QTE)
buildCameraPage(tabs.Camera)
buildSettingsPage(tabs.Settings)
fluentWindow:SelectTab(1)
screenGui = fluent.GUI
fluent:Notify({
Title = "Potent loaded",
Content = "Fluent interface ready. Right Shift toggles the menu.",
Duration = 4,
})
STATE.onCleanup(function()
if fluent then
pcall(function() fluent:Destroy() end)
end
end)
end
local function buildKeyHighlighter()
keyHighlighter = Drawing.new("Text")
keyHighlighter.Visible = false
keyHighlighter.Center = true
keyHighlighter.Outline = true
keyHighlighter.Font = Drawing.Fonts.Plex
keyHighlighter.Size = 64
keyHighlighter.Color = Color3.fromRGB(255, 255, 255)
STATE.onCleanup(function()
keyHighlighter:Remove()
end)
end
local function onHeartbeat()
tryAutoStart()
if not qteKey.Visible then
if statusLabel then
statusLabel.Text = "Status: Idle"
end
keyHighlighter.Visible = false
return
end
local letter = qteLetter.Text
if not VALID_KEYS[letter] then
keyHighlighter.Visible = false
return
end
if Potent.highlighterEnabled then
local camera = workspace.CurrentCamera
keyHighlighter.Position = Vector2.new(camera.ViewportSize.X / 2, camera.ViewportSize.Y * 0.35)
keyHighlighter.Text = letter
keyHighlighter.Visible = true
else
keyHighlighter.Visible = false
end
if not Potent.autoQteEnabled or not isrbxactive() then
if statusLabel then
statusLabel.Text = "Status: Idle"
end
return
end
if statusLabel then
statusLabel.Text = "Status: Pressing " .. letter
end
local now = os.clock()
if now - Potent.lastTapAt < Potent.tapInterval then
return
end
Potent.lastTapAt = now
keytap(string.byte(letter))
end
local function onInitError(err)
warn("Potent Auto QTE failed to initialize.")
warn(err)
warn(debug.traceback())
end
local function initializeScript()
loadConfig()
buildUi()
buildKeyHighlighter()
STATE.connect(userInputService.InputBegan, function(input, processed)
if processed then
return
end
if input.KeyCode == MENU_TOGGLE_KEY then
screenGui.Enabled = not screenGui.Enabled
return
end
if input.UserInputType == Enum.UserInputType.MouseButton2 and Potent.freeCamEnabled then
local focusPosition = getThirdPersonFocus()
if focusPosition then
beginFreeCam(focusPosition)
end
end
end)
STATE.connect(userInputService.InputEnded, function(input)
if input.UserInputType == Enum.UserInputType.MouseButton2 then
endFreeCam()
end
end)
STATE.connect(userInputService.InputChanged, function(input)
if not freeCamActive then
return
end
if input.UserInputType == Enum.UserInputType.MouseMovement then
orbitYaw = orbitYaw - input.Delta.X * FREE_CAM_SENSITIVITY
orbitPitch =
math.clamp(orbitPitch - input.Delta.Y * FREE_CAM_SENSITIVITY, -FREE_CAM_PITCH_LIMIT, FREE_CAM_PITCH_LIMIT)
elseif input.UserInputType == Enum.UserInputType.MouseWheel then
orbitDistance = math.clamp(orbitDistance - input.Position.Z * FREE_CAM_ZOOM_SENSITIVITY, FREE_CAM_MIN_DISTANCE, FREE_CAM_MAX_DISTANCE)
end
end)
pcall(function()
runService:UnbindFromRenderStep("PotentFreeCam")
end)
runService:BindToRenderStep("PotentFreeCam", FREE_CAM_RENDER_PRIORITY, onFreeCamRenderStep)
STATE.onCleanup(function()
runService:UnbindFromRenderStep("PotentFreeCam")
userInputService.MouseBehavior = Enum.MouseBehavior.Default
local camPart = workspace:FindFirstChild("campart")
if camPart and preFreeCamCFrame then
camPart.CFrame = preFreeCamCFrame
end
end)
STATE.connect(runService.Heartbeat, onHeartbeat)
end
xpcall(initializeScript, onInitError)Review the source before using it. Executions count successful copies, capped at 10 per user and network per script in 24 hours.
Community discussion
0Start the conversation.


Your community, in one place