Infinite waypoint tween looper
Key RequiredUniversal

Infinite waypoint tween looper

Universal ScriptMediorceExploiterMediorceExploiter 616 views 131 executesUpdated Jan 5, 2026
Unrated
00
Lua Script•375 lines (10098 chars)
--// Infinite Waypoint Tween Looper (Client-sided)
--// LocalScript: StarterPlayerScripts
--// Add unlimited waypoints, then loop tween through them.

local Players = game:GetService("Players")
local TweenService = game:GetService("TweenService")
local CoreGui = game:GetService("CoreGui")

local player = Players.LocalPlayer

-- =========================
-- CONFIG (easy to adjust)
-- =========================
local GUI_NAME = "InfiniteWaypointTweenLooperGui"

-- Choose ONE timing mode:
local USE_SPEED_MODE = true            -- true: uses STUDS_PER_SECOND, false: uses FIXED_TWEEN_TIME
local STUDS_PER_SECOND = 30            -- movement speed when USE_SPEED_MODE = true
local FIXED_TWEEN_TIME = 1.0           -- seconds per segment when USE_SPEED_MODE = false

local MIN_TWEEN_TIME = 0.15            -- clamps duration
local MAX_TWEEN_TIME = 6.0

local EASING_STYLE = Enum.EasingStyle.Sine
local EASING_DIR = Enum.EasingDirection.InOut

local WAIT_AT_POINT = 0.05             -- pause at each waypoint
local CONTROL_AUTOROTATE = true        -- smoother look while tweening

-- =========================
-- cleanup old gui
-- =========================
do
	local old = CoreGui:FindFirstChild(GUI_NAME)
	if old then old:Destroy() end
end

-- =========================
-- helpers
-- =========================
local function getCharacter()
	return player.Character or player.CharacterAdded:Wait()
end

local function getRootPart(char)
	if not char then return nil end
	return char:FindFirstChild("HumanoidRootPart") or char.PrimaryPart
end

local function getHumanoid(char)
	return char and char:FindFirstChildOfClass("Humanoid") or nil
end

local function clamp(x, a, b)
	if x < a then return a end
	if x > b then return b end
	return x
end

local function computeTweenTime(fromPos: Vector3, toPos: Vector3)
	if not USE_SPEED_MODE then
		return clamp(FIXED_TWEEN_TIME, MIN_TWEEN_TIME, MAX_TWEEN_TIME)
	end
	local dist = (toPos - fromPos).Magnitude
	local t = dist / math.max(STUDS_PER_SECOND, 0.01)
	return clamp(t, MIN_TWEEN_TIME, MAX_TWEEN_TIME)
end

local function makeDraggable(frame, handle)
	handle = handle or frame
	local dragging = false
	local dragStart, startPos

	local function update(input)
		local delta = input.Position - dragStart
		frame.Position = UDim2.new(
			startPos.X.Scale, startPos.X.Offset + delta.X,
			startPos.Y.Scale, startPos.Y.Offset + delta.Y
		)
	end

	handle.InputBegan:Connect(function(input)
		if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
			dragging = true
			dragStart = input.Position
			startPos = frame.Position

			input.Changed:Connect(function()
				if input.UserInputState == Enum.UserInputState.End then
					dragging = false
				end
			end)
		end
	end)

	handle.InputChanged:Connect(function(input)
		if (input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch) and dragging then
			update(input)
		end
	end)
end

-- =========================
-- GUI
-- =========================
local gui = Instance.new("ScreenGui")
gui.Name = GUI_NAME
gui.ResetOnSpawn = false
gui.Parent = CoreGui

local main = Instance.new("Frame")
main.Name = "Main"
main.Size = UDim2.new(0, 320, 0, 320)
main.Position = UDim2.new(0, 20, 0, 120)
main.BackgroundColor3 = Color3.fromRGB(20, 20, 20)
main.BorderSizePixel = 0
main.Parent = gui

local corner = Instance.new("UICorner")
corner.CornerRadius = UDim.new(0, 10)
corner.Parent = main

local header = Instance.new("TextButton")
header.Name = "Header"
header.Size = UDim2.new(1, 0, 0, 32)
header.BackgroundColor3 = Color3.fromRGB(30, 30, 30)
header.BorderSizePixel = 0
header.Text = "Infinite Waypoint Tween Looper"
header.Font = Enum.Font.GothamBold
header.TextSize = 14
header.TextColor3 = Color3.fromRGB(235, 235, 235)
header.AutoButtonColor = false
header.Parent = main

local headerCorner = Instance.new("UICorner")
headerCorner.CornerRadius = UDim.new(0, 10)
headerCorner.Parent = header

local headerMask = Instance.new("Frame")
headerMask.Size = UDim2.new(1, 0, 0, 10)
headerMask.Position = UDim2.new(0, 0, 1, -10)
headerMask.BackgroundColor3 = header.BackgroundColor3
headerMask.BorderSizePixel = 0
headerMask.Parent = header

local function makeBtn(name, text, posY, height)
	height = height or 34
	local b = Instance.new("TextButton")
	b.Name = name
	b.Size = UDim2.new(1, -20, 0, height)
	b.Position = UDim2.new(0, 10, 0, posY)
	b.BackgroundColor3 = Color3.fromRGB(45, 45, 45)
	b.BorderSizePixel = 0
	b.Text = text
	b.Font = Enum.Font.Gotham
	b.TextSize = 14
	b.TextColor3 = Color3.fromRGB(240, 240, 240)
	b.Parent = main

	local c = Instance.new("UICorner")
	c.CornerRadius = UDim.new(0, 8)
	c.Parent = b

	return b
end

local btnAdd = makeBtn("Add", "Add Waypoint (Current Position)", 44)
local btnRemove = makeBtn("RemoveLast", "Remove Last Waypoint", 84)
local btnClear = makeBtn("ClearAll", "Clear All Waypoints", 124)
local btnLoop = makeBtn("ToggleLoop", "Enable Loop: OFF", 164)

local listLabel = Instance.new("TextLabel")
listLabel.Size = UDim2.new(1, -20, 0, 18)
listLabel.Position = UDim2.new(0, 10, 0, 206)
listLabel.BackgroundTransparency = 1
listLabel.Text = "Waypoints:"
listLabel.Font = Enum.Font.GothamBold
listLabel.TextSize = 12
listLabel.TextColor3 = Color3.fromRGB(200, 200, 200)
listLabel.TextXAlignment = Enum.TextXAlignment.Left
listLabel.Parent = main

local list = Instance.new("ScrollingFrame")
list.Name = "WaypointList"
list.Size = UDim2.new(1, -20, 1, -232)
list.Position = UDim2.new(0, 10, 0, 228)
list.BackgroundColor3 = Color3.fromRGB(26, 26, 26)
list.BorderSizePixel = 0
list.ScrollBarThickness = 6
list.CanvasSize = UDim2.new(0, 0, 0, 0)
list.Parent = main

local listCorner = Instance.new("UICorner")
listCorner.CornerRadius = UDim.new(0, 8)
listCorner.Parent = list

local layout = Instance.new("UIListLayout")
layout.Padding = UDim.new(0, 6)
layout.SortOrder = Enum.SortOrder.LayoutOrder
layout.Parent = list

local pad = Instance.new("UIPadding")
pad.PaddingTop = UDim.new(0, 8)
pad.PaddingBottom = UDim.new(0, 8)
pad.PaddingLeft = UDim.new(0, 8)
pad.PaddingRight = UDim.new(0, 8)
pad.Parent = list

makeDraggable(main, header)

-- =========================
-- Data + UI rendering
-- =========================
local waypoints = {} :: {CFrame}
local loopEnabled = false
local loopToken = 0

local function setLoopUi(on)
	btnLoop.Text = on and "Enable Loop: ON" or "Enable Loop: OFF"
	btnLoop.BackgroundColor3 = on and Color3.fromRGB(60, 110, 60) or Color3.fromRGB(45, 45, 45)
end

local function clearWaypointListUi()
	for _, child in ipairs(list:GetChildren()) do
		if child:IsA("Frame") then
			child:Destroy()
		end
	end
end

local function addWaypointRow(i: number, cf: CFrame)
	local row = Instance.new("Frame")
	row.Size = UDim2.new(1, 0, 0, 26)
	row.BackgroundColor3 = Color3.fromRGB(38, 38, 38)
	row.BorderSizePixel = 0
	row.LayoutOrder = i
	row.Parent = list

	local rc = Instance.new("UICorner")
	rc.CornerRadius = UDim.new(0, 6)
	rc.Parent = row

	local txt = Instance.new("TextLabel")
	txt.BackgroundTransparency = 1
	txt.Size = UDim2.new(1, -10, 1, 0)
	txt.Position = UDim2.new(0, 8, 0, 0)
	txt.Font = Enum.Font.Gotham
	txt.TextSize = 12
	txt.TextColor3 = Color3.fromRGB(230, 230, 230)
	txt.TextXAlignment = Enum.TextXAlignment.Left

	local p = cf.Position
	txt.Text = string.format("#%d  (%.1f, %.1f, %.1f)", i, p.X, p.Y, p.Z)
	txt.Parent = row
end

local function refreshWaypointUi()
	clearWaypointListUi()

	for i, cf in ipairs(waypoints) do
		addWaypointRow(i, cf)
	end

	-- update canvas size
	task.defer(function()
		local total = layout.AbsoluteContentSize.Y + 16
		list.CanvasSize = UDim2.new(0, 0, 0, total)
	end)
end

-- =========================
-- Tween Loop
-- =========================
local function tweenRootTo(root: BasePart, target: CFrame)
	local t = computeTweenTime(root.Position, target.Position)
	local ti = TweenInfo.new(t, EASING_STYLE, EASING_DIR)
	local tw = TweenService:Create(root, ti, {CFrame = target})
	tw:Play()
	return tw
end

local function runLoop(myToken: number)
	local savedAutoRotate: boolean? = nil

	while loopEnabled and loopToken == myToken do
		-- Need at least 2 waypoints to loop
		if #waypoints < 2 then
			task.wait(0.1)
			continue
		end

		local char = player.Character
		local root = getRootPart(char)
		local hum = getHumanoid(char)

		if not (char and root) then
			task.wait(0.1)
			continue
		end

		if CONTROL_AUTOROTATE and hum then
			savedAutoRotate = hum.AutoRotate
			hum.AutoRotate = false
		end

		-- Loop through in order, forever
		for i = 1, #waypoints do
			if not (loopEnabled and loopToken == myToken) then break end

			-- If waypoints changed during the loop, clamp i safely
			if i > #waypoints then break end

			local target = waypoints[i]
			local tw = tweenRootTo(root, target)
			tw.Completed:Wait()

			if not (loopEnabled and loopToken == myToken) then break end
			task.wait(WAIT_AT_POINT)

			-- Refresh root if character changed mid-loop
			char = player.Character
			root = getRootPart(char)
			hum = getHumanoid(char)
			if not (char and root) then break end
		end
	end

	-- restore autorotate if possible
	local char = player.Character
	local hum = getHumanoid(char)
	if CONTROL_AUTOROTATE and hum and savedAutoRotate ~= nil then
		hum.AutoRotate = savedAutoRotate
	end
end

-- =========================
-- Button wiring
-- =========================
btnAdd.MouseButton1Click:Connect(function()
	local char = getCharacter()
	local root = getRootPart(char)
	if not root then return end

	table.insert(waypoints, root.CFrame)
	refreshWaypointUi()
end)

btnRemove.MouseButton1Click:Connect(function()
	if #waypoints > 0 then
		table.remove(waypoints, #waypoints)
		refreshWaypointUi()
	end
end)

btnClear.MouseButton1Click:Connect(function()
	table.clear(waypoints)
	refreshWaypointUi()
end)

btnLoop.MouseButton1Click:Connect(function()
	loopEnabled = not loopEnabled
	setLoopUi(loopEnabled)

	loopToken += 1
	local myToken = loopToken

	if loopEnabled then
		task.spawn(function()
			runLoop(myToken)
		end)
	end
end)

setLoopUi(false)
refreshWaypointUi()

Features & Information

It's so peak, this masterpiece was generated by ChatGPT 5.2 It just makes waypoints, and then tweens you between them.
#Peak

Community Comments (1)

CidXScriptCidXScriptJan 5, 2026

w

More Scripts for Universal Scripts