
Key Required

if getgenv().TAS_PlayGUI_Running then
pcall(function() getgenv().TAS_PlayGUI_Disconnect() end)
task.wait(0.2)
end
getgenv().TAS_PlayGUI_Running = true
local RunService = game:GetService("RunService")
local HttpService = game:GetService("HttpService")
local Players = game:GetService("Players")
local Workspace = game:GetService("Workspace")
local StarterGui = game:GetService("StarterGui")
local LocalPlayer = Players.LocalPlayer
local REPO_BASE = "https://raw.githubusercontent.com/manningian744-droid/Open-Source-Autoplay/refs/heads/main/"
local MANIFEST_URL = REPO_BASE .. "manifest.txt"
local FOLDER = "TAS_Recorder"
local DISPLAY_NAMES = {
["boot1"] = "Bootcamp (Left)",
["boot2"] = "Bootcamp (Middle)",
["boot3"] = "Bootcamp (Right)",
["cave"] = "Cave Chaos",
["collo"] = "Colosseum Climb",
["collo2"] = "Colosseum Climb (Faster)",
["cons"] = "Construct Course",
["hill"] = "Hill Hike",
["lava"] = "Lava Dash",
["obsta"] = "Obstacle Course",
["pond"] = "Pond Pier",
["rickety"] = "Rickety Rails",
["rock1"] = "Rockwall (Left)",
["rock2"] = "Rockwall (Middle)",
["rock3"] = "Rockwall (Right)",
["spin"] = "Spinner",
["sweep"] = "Sweeper",
["tight"] = "Tightrope",
["unstab"] = "Unstable Savannah",
["caveclip"] = "Cave Chaos (Clip)",
["unstabclip"] = "Unstable Savannah (Clip)",
}
local function notify(text, title, dur)
pcall(function()
StarterGui:SetCore("SendNotification", {
Title = title or "TAS Player", Text = text or "", Duration = dur or 3
})
end)
end
-- Reads manifest.txt from the repo, returns list of {id, label} in order
local function FetchManifest()
local ok, content = pcall(function()
return game:HttpGet(MANIFEST_URL, true)
end)
if not ok or not content or #content < 3 then return nil end
local runs = {}
for line in content:gmatch("[^\r\n]+") do
line = line:match("^%s*(.-)%s*$")
if line ~= "" then
local id = line:gsub("%.json$", "")
local label = DISPLAY_NAMES[id] or id
table.insert(runs, { id = id, label = label })
end
end
return #runs > 0 and runs or nil
end
-- Downloads any runs listed in the manifest that aren't already on disk
local function EnsureRuns(runs)
if not isfolder(FOLDER) then makefolder(FOLDER) end
local downloaded = 0
local skipped = 0
for _, run in ipairs(runs) do
local path = FOLDER .. "/" .. run.id .. ".json"
if isfile(path) then
skipped = skipped + 1
else
local ok, content = pcall(function()
return game:HttpGet(REPO_BASE .. run.id .. ".json", true)
end)
if ok and content and #content > 10 then
pcall(function() writefile(path, content) end)
downloaded = downloaded + 1
end
end
end
if downloaded > 0 then
notify("Downloaded " .. downloaded .. " new run(s). " .. skipped .. " already existed.", "LifeHub", 5)
end
end
-- Playback engine
local ValToStateName = {}
for _, s in ipairs(Enum.HumanoidStateType:GetEnumItems()) do
ValToStateName[s.Value] = s.Name
end
local KeepEnabled = {
[Enum.HumanoidStateType.Dead] = true,
[Enum.HumanoidStateType.GettingUp] = true,
[Enum.HumanoidStateType.Landed] = true,
[Enum.HumanoidStateType.None] = true,
}
local function CFrameToQuat(cf)
local ax, ang = cf:ToAxisAngle()
local sh = math.sin(ang / 2)
return ax.X*sh, ax.Y*sh, ax.Z*sh, math.cos(ang / 2)
end
local function QuatToCFrame(x, y, z, qx, qy, qz, qw)
return CFrame.new(x, y, z, qx, qy, qz, qw)
end
local function NormaliseFrame(f)
if type(f.CF) == "table" then
if #f.CF == 12 then
local cf = CFrame.new(table.unpack(f.CF))
local qx,qy,qz,qw = CFrameToQuat(cf)
f.CF = {cf.X, cf.Y, cf.Z, qx, qy, qz, qw}
elseif #f.CF == 6 then
local cf = CFrame.new(f.CF[1],f.CF[2],f.CF[3]) * CFrame.fromEulerAnglesYXZ(f.CF[4],f.CF[5],f.CF[6])
local qx,qy,qz,qw = CFrameToQuat(cf)
f.CF = {cf.X, cf.Y, cf.Z, qx, qy, qz, qw}
end
end
if type(f.CCF) == "table" then
if #f.CCF == 12 then
local ccf = CFrame.new(table.unpack(f.CCF))
local qx,qy,qz,qw = CFrameToQuat(ccf)
f.CCF = {ccf.X, ccf.Y, ccf.Z, qx, qy, qz, qw}
elseif #f.CCF == 6 then
local ccf = CFrame.new(f.CCF[1],f.CCF[2],f.CCF[3]) * CFrame.fromEulerAnglesYXZ(f.CCF[4],f.CCF[5],f.CCF[6])
local qx,qy,qz,qw = CFrameToQuat(ccf)
f.CCF = {ccf.X, ccf.Y, ccf.Z, qx, qy, qz, qw}
end
end
-- AN (animation data) is already a plain table, no conversion needed
end
local PlayConn = nil
local IsPlaying = false
local CurrentRunName = ""
local function StopPlayback()
if PlayConn then PlayConn:Disconnect(); PlayConn = nil end
IsPlaying = false
getgenv().TAS_IsPlaying = false
CurrentRunName = ""
local char = LocalPlayer.Character
if not char then return end
local root = char:FindFirstChild("HumanoidRootPart")
if root then
root.Anchored = false
root.Velocity = Vector3.zero
root.RotVelocity = Vector3.zero
end
local hum = char:FindFirstChild("Humanoid")
if hum then
for _, st in ipairs(Enum.HumanoidStateType:GetEnumItems()) do
pcall(function() hum:SetStateEnabled(st, true) end)
end
pcall(function()
if hum:GetState() ~= Enum.HumanoidStateType.GettingUp then
hum:ChangeState(Enum.HumanoidStateType.GettingUp)
end
end)
end
end
local function PlayRun(label, rawJson)
if IsPlaying then StopPlayback(); task.wait(0.05) end
local ok, data = pcall(HttpService.JSONDecode, HttpService, rawJson)
if not ok or type(data) ~= "table" or type(data[1]) ~= "table" or type(data[2]) ~= "table" then
notify("Bad data for: " .. label, "TAS Error"); return
end
local frames = {}
for _, seg in ipairs(data[1]) do
for _, f in ipairs(seg) do NormaliseFrame(f); table.insert(frames, f) end
end
for _, f in ipairs(data[2]) do
NormaliseFrame(f); table.insert(frames, f)
end
if #frames == 0 then notify("No frames in: " .. label, "TAS Error"); return end
local char = LocalPlayer.Character
local root = char and char:FindFirstChild("HumanoidRootPart")
local hum = char and char:FindFirstChild("Humanoid")
if not root then notify("Respawn first!", "TAS Error"); return end
IsPlaying = true
CurrentRunName = label
getgenv().TAS_IsPlaying = true
root.Anchored = false
if hum then
for _, st in ipairs(Enum.HumanoidStateType:GetEnumItems()) do
if not KeepEnabled[st] then
pcall(function() hum:SetStateEnabled(st, false) end)
end
end
end
notify("▶ " .. label, "TAS Player", 2)
local t0 = os.clock()
local idx = 1
PlayConn = RunService.Heartbeat:Connect(function()
if not char or not char.Parent or not root or not root.Parent then
StopPlayback(); return
end
if hum and hum.Health <= 0 then StopPlayback(); return end
local elapsed = os.clock() - t0
while idx < #frames and frames[idx+1] and frames[idx+1].T <= elapsed do
idx = idx + 1
end
local fA = frames[idx]
local fB = frames[idx + 1]
if fB and type(fA)=="table" and type(fB)=="table"
and fA.CF and fB.CF and fA.V and fB.V and fA.RV and fB.RV then
local dt = fB.T - fA.T
local alpha = (dt > 0) and math.clamp((elapsed - fA.T) / dt, 0, 1) or 0
root.CFrame = QuatToCFrame(table.unpack(fA.CF)):Lerp(QuatToCFrame(table.unpack(fB.CF)), alpha)
if type(fA.CCF)=="table" and type(fB.CCF)=="table" then
Workspace.CurrentCamera.CFrame =
QuatToCFrame(table.unpack(fA.CCF)):Lerp(QuatToCFrame(table.unpack(fB.CCF)), alpha)
end
local vA = Vector3.new(table.unpack(fA.V)); local vB = Vector3.new(table.unpack(fB.V))
local rvA = Vector3.new(table.unpack(fA.RV)); local rvB = Vector3.new(table.unpack(fB.RV))
local cv = vA:Lerp(vB, alpha)
local crv = rvA:Lerp(rvB, alpha)
for _, p in ipairs(char:GetDescendants()) do
if p:IsA("BasePart") then p.Velocity = cv; p.RotVelocity = crv end
end
if hum and fA.HS then
local sname = type(fA.HS)=="number" and ValToStateName[fA.HS] or fA.HS
if sname and sname ~= "None" then
local cur = hum:GetState().Name
if cur ~= sname then
local enum = Enum.HumanoidStateType[sname]
if enum then pcall(function() hum:ChangeState(enum) end) end
end
end
end
-- Replay animations recorded in this frame
if type(fA.AN) == "table" then
local animator = hum and hum:FindFirstChildOfClass("Animator")
if animator then
local desiredAnims = {}
for _, animData in ipairs(fA.AN) do
if animData.Id and animData.Id ~= "" then
desiredAnims[animData.Id] = animData
end
end
-- Stop tracks that shouldn't be playing
for _, track in ipairs(animator:GetPlayingAnimationTracks()) do
local id = track.Animation and track.Animation.AnimationId
if id and not desiredAnims[id] then
track:Stop(0)
end
end
-- Start or update tracks that should be playing
for animId, animData in pairs(desiredAnims) do
local found = false
for _, track in ipairs(animator:GetPlayingAnimationTracks()) do
if track.Animation and track.Animation.AnimationId == animId then
found = true
track:AdjustSpeed(animData.Speed or 1)
track:AdjustWeight(animData.Weight or 1, 0)
pcall(function() track.TimePosition = animData.Pos or 0 end)
break
end
end
if not found then
local anim = Instance.new("Animation")
anim.AnimationId = animId
local ok, track = pcall(function()
return animator:LoadAnimation(anim)
end)
if ok and track then
track:Play(0, animData.Weight or 1, animData.Speed or 1)
pcall(function() track.TimePosition = animData.Pos or 0 end)
end
anim:Destroy()
end
end
end
end
else
StopPlayback()
notify("✔ Finished: " .. label, "TAS Player", 3)
end
end)
end
local function LoadRunFromFile(id, label)
local path = FOLDER .. "/" .. id .. ".json"
if not isfile(path) then
notify("File not found: " .. id .. ".json", "TAS Error"); return
end
local ok, content = pcall(readfile, path)
if not ok or not content then
notify("Could not read: " .. label, "TAS Error"); return
end
PlayRun(label, content)
end
-- Fetch manifest and download missing runs before building the GUI
local GITHUB_API = "https://api.github.com/repos/manningian744-droid/Open-Source-Autoplay/commits?path="
local TIMESTAMPS_FILE = FOLDER .. "/timestamps.json"
local function GetLocalTimestamps()
if not isfolder(FOLDER) then return {} end
if not isfile(TIMESTAMPS_FILE) then return {} end
local ok, content = pcall(readfile, TIMESTAMPS_FILE)
if not ok or not content or #content < 2 then return {} end
local ok2, data = pcall(function() return HttpService:JSONDecode(content) end)
return (ok2 and type(data) == "table") and data or {}
end
local function SaveLocalTimestamps(timestamps)
pcall(function()
writefile(TIMESTAMPS_FILE, HttpService:JSONEncode(timestamps))
end)
end
local function GetRemoteCommitDate(filename)
local ok, content = pcall(function()
return game:HttpGet(GITHUB_API .. filename .. "&per_page=1", true)
end)
if not ok or not content or #content < 5 then return nil end
local ok2, data = pcall(function() return HttpService:JSONDecode(content) end)
if not ok2 or type(data) ~= "table" or not data[1] then return nil end
local commit = data[1].commit
if not commit then return nil end
local date = commit.committer and commit.committer.date
return date
end
local function EnsureRunsWithDateCheck(runs)
if not isfolder(FOLDER) then makefolder(FOLDER) end
local timestamps = GetLocalTimestamps()
local downloaded = 0
local updated = 0
local skipped = 0
for _, run in ipairs(runs) do
local filename = run.id .. ".json"
local path = FOLDER .. "/" .. filename
local exists = isfile(path)
local remoteDate = GetRemoteCommitDate(filename)
local localDate = timestamps[filename]
local needsUpdate = false
if not exists then
needsUpdate = true
elseif remoteDate and localDate and remoteDate ~= localDate then
needsUpdate = true
elseif remoteDate and not localDate then
needsUpdate = true
end
if needsUpdate then
local ok, content = pcall(function()
return game:HttpGet(REPO_BASE .. filename, true)
end)
if ok and content and #content > 10 then
pcall(function() writefile(path, content) end)
if remoteDate then
timestamps[filename] = remoteDate
end
if exists then
updated = updated + 1
else
downloaded = downloaded + 1
end
end
else
skipped = skipped + 1
end
end
SaveLocalTimestamps(timestamps)
if updated > 0 and downloaded > 0 then
notify("Updated " .. updated .. " and downloaded " .. downloaded .. " new run(s).", "LifeHub", 5)
elseif updated > 0 then
notify("Updated " .. updated .. " run(s) to latest versions.", "LifeHub", 5)
elseif downloaded > 0 then
notify("Downloaded " .. downloaded .. " new run(s).", "LifeHub", 5)
end
end
local runs = FetchManifest()
if not runs then
if not isfolder(FOLDER) then makefolder(FOLDER) end
local allFiles = listfiles(FOLDER)
runs = {}
for _, path in ipairs(allFiles) do
local filename = path:match("([^/\\]+)$") or path
if filename:match("%.json$") and filename ~= "timestamps.json" then
local id = filename:gsub("%.json$", "")
local label = DISPLAY_NAMES[id] or id
table.insert(runs, { id = id, label = label })
end
end
table.sort(runs, function(a, b) return a.id < b.id end)
notify("Could not fetch manifest — showing local runs only.", "LifeHub", 4)
else
EnsureRunsWithDateCheck(runs)
end
-- GUI
local Rayfield = loadstring(game:HttpGet("https://sirius.menu/rayfield"))()
local Window = Rayfield:CreateWindow({
Name = "TAS Player",
LoadingTitle = "TAS Player",
LoadingSubtitle = "Loading runs...",
ConfigurationSaving = { Enabled = false },
Discord = { Enabled = false },
KeySystem = false,
})
local RunTab = Window:CreateTab("Runs", 4483362458)
RunTab:CreateSection("Saved Runs (" .. #runs .. ") — click to play")
for _, run in ipairs(runs) do
RunTab:CreateButton({
Name = run.label,
Description = run.id .. ".json",
Callback = function()
LoadRunFromFile(run.id, run.label)
end,
})
end
local CtrlTab = Window:CreateTab("Controls", 4483362458)
CtrlTab:CreateSection("Playback")
CtrlTab:CreateButton({
Name = "Stop Playback",
Description = "Stops any active TAS playback",
Callback = function()
StopPlayback()
notify("Playback stopped.", "TAS Player", 2)
end,
})
CtrlTab:CreateSection("Script")
CtrlTab:CreateButton({
Name = "Unload GUI",
Description = "Removes this GUI and cleans up",
Callback = function()
getgenv().TAS_PlayGUI_Disconnect()
end,
})
getgenv().TAS_PlayGUI_Disconnect = function()
StopPlayback()
pcall(function() Rayfield:Destroy() end)
getgenv().TAS_PlayGUI_Running = false
notify("TAS Play GUI unloaded.", "TAS Player")
end
notify("TAS Player ready! " .. #runs .. " run(s) loaded.", "TAS Player", 4)No comments yet for this script.

![Custom Character Selector [TRD]](https://cdn.kocakz.me/images/78fe18a1b86b83ae0a9c6eb98963df7d5e53ea616520e04dc355d4d3060c926d.webp)

