M
Description
- Auto Collect Orbs - Auto Start - Auto Roll - Auto Merge - Auto Buy - Auto Equip Best Spinner
GAMESpinner Battles
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=6aade062819ebddb2a23d61c"))()
end)
end)
--[[rscripts:analytics:end]]
-- Spinner Battles | @hidevin | ObsidianUltra
local Repo = "https://raw.githubusercontent.com/joustingmatch/ObsidianUltra/main/"
local Library = loadstring(game:HttpGet(Repo .. "Library.lua"))()
local ThemeManager = loadstring(game:HttpGet(Repo .. "addons/ThemeManager.lua"))()
local SaveManager = loadstring(game:HttpGet(Repo .. "addons/SaveManager.lua"))()
local Players = game:GetService("Players")
local RS = game:GetService("ReplicatedStorage")
local LocalPlayer = Players.LocalPlayer
local Options = Library.Options
local Toggles = Library.Toggles
-- Design tokens (UI_STYLE.json)
local C_BG = Color3.fromRGB(13, 13, 13) -- #0d0d0d
local C_CARD = Color3.fromRGB(40, 40, 40) -- #282828
local C_BORDER = Color3.fromRGB(58, 58, 58) -- #3a3a3a
local C_ACCENT = Color3.fromRGB(88, 101, 242) -- #5865F2
local C_WHITE = Color3.fromRGB(255, 255, 255)
local Window = Library:CreateWindow({
Title = "@hidevin",
Footer = "Spinner Battles | Leave a like on Rscripts if it works. @hidevin",
ToggleKeybind = Enum.KeyCode.RightShift,
DisableSearch = true, -- UI_STYLE: show_search_bar = false
Minimizable = true,
Center = true,
AutoShow = true,
CornerRadius = 10, -- UI_STYLE card border_radius
})
-- Apply theme tokens over the default scheme
pcall(function()
Library.Scheme.BackgroundColor = C_BG
Library.Scheme.MainColor = C_CARD
Library.Scheme.OutlineColor = C_BORDER
Library.Scheme.AccentColor = C_ACCENT
Library.Scheme.FontColor = C_WHITE
Library.Scheme.BlueColor = C_ACCENT
if Library.UpdateColorsUsingRegistry then
Library:UpdateColorsUsingRegistry()
end
end)
pcall(function()
Window:SetCornerRadius(10)
end)
-- Tabs (UI_STYLE structure minus Rebirth: game has no rebirth service)
local Tabs = {
Main = Window:AddTab({ Name = "Main", Icon = "home", Description = "Dashboard" }),
Farming = Window:AddTab({ Name = "Farming", Icon = "sprout", Description = "Orbs and battles" }),
Inventory = Window:AddTab({ Name = "Inventory", Icon = "backpack", Description = "Rolls, merges and team" }),
Settings = Window:AddTab({ Name = "Settings", Icon = "settings", Description = "Config and safety" }),
}
-- Knit remotes (verified live on pincoat1 session)
local Services = RS:WaitForChild("Packages"):WaitForChild("Knit"):WaitForChild("Services")
local function RF(svc, name)
local s = Services:FindFirstChild(svc)
if not s then return nil end
local rf = s:FindFirstChild("RF")
if not rf then return nil end
return rf:FindFirstChild(name)
end
local function invoke(svc, name, ...)
local fn = RF(svc, name)
if not fn then return false, "missing " .. svc .. "." .. name end
local ok, res = pcall(function(...)
return fn:InvokeServer(...)
end, ...)
return ok, res
end
local function getPlayerData()
local ok, RC = pcall(function()
return require(RS:WaitForChild("Replica"):WaitForChild("ReplicaController"))
end)
if not ok or not RC or not RC._replicas then return nil end
for _, rep in pairs(RC._replicas) do
if rep and rep.Data and rep.Data.Blades then
return rep.Data
end
end
return nil
end
local function bladePower(id, level)
local ok, cfg = pcall(function()
return require(RS:WaitForChild("Shared"):WaitForChild("Config"):WaitForChild("BladeConfig"))
end)
if not ok or not cfg then return 0 end
local b = cfg[id]
if not b then return 0 end
return (tonumber(b.BasePower) or 0) * 1000 + (tonumber(level) or 0)
end
-- Main tab: info only, zero mechanics (GAME_FEATURES rule)
do
Tabs.Main:AddPlayerInfo("MainBanner", {
Title = "Spinner Battles",
Description = { "Roll spinners, merge 3 of a kind, send your team into the arena." },
ThumbnailType = "HeadShot",
Height = 84,
})
local Status = Tabs.Main:AddLeftGroupbox("Status", "activity")
Status:AddLabel("SessionTime", { Text = "Session: --", DoesWrap = true })
Status:AddLabel("WalletInfo", { Text = "Coins: --", DoesWrap = true })
Status:AddLabel("TeamInfo", { Text = "Team: --", DoesWrap = true })
local Help = Tabs.Main:AddRightGroupbox("Info", "info")
Help:AddLabel("Farming lives under the Farming tab, rolls and team under Inventory.", true)
Help:AddLabel("Every Auto loops about once per second. Tune each delay slider.", true)
end
-- Farming tab: >1 feature so sub-tabs are mandatory
local OrbSub = Tabs.Farming:AddSubTab({ Name = "Auto-Collect", Icon = "magnet" })
local QuestSub = Tabs.Farming:AddSubTab({ Name = "Auto-Quest", Icon = "swords" })
do
local Collecting = OrbSub:AddLeftGroupbox("Collecting", "magnet")
Collecting:AddToggle("AutoOrbs", { Text = "Auto Collect Orbs", Default = false, Tooltip = "Clicks orb detectors and claims EnergyOrbs" })
Collecting:AddSlider("OrbDelay", { Text = "Loop delay", Default = 1, Min = 0.5, Max = 10, Rounding = 1, Suffix = "s" })
local Battle = QuestSub:AddLeftGroupbox("Battle", "swords")
Battle:AddToggle("AutoStart", { Text = "Auto Start", Default = false, Tooltip = "Starts arena battles (BattleService.Start)" })
Battle:AddSlider("StartDelay", { Text = "Loop delay", Default = 1, Min = 0.5, Max = 10, Rounding = 1, Suffix = "s" })
end
-- Inventory tab: rolling / merging / purchasing / team split into sub-tabs
local RollSub = Tabs.Inventory:AddSubTab({ Name = "Rolling", Icon = "dices" })
local MergeSub = Tabs.Inventory:AddSubTab({ Name = "Merging", Icon = "combine" })
local BuySub = Tabs.Inventory:AddSubTab({ Name = "Purchasing", Icon = "shopping-cart" })
local TeamSub = Tabs.Inventory:AddSubTab({ Name = "Team", Icon = "users" })
local UpgradeSub = Tabs.Inventory:AddSubTab({ Name = "Upgrades", Icon = "arrow-big-up" })
do
local Rolling = RollSub:AddLeftGroupbox("Rolling", "dices")
Rolling:AddToggle("AutoRoll", { Text = "Auto Roll", Default = false, Tooltip = "Rolls a spinner (RollService.Summon)" })
Rolling:AddSlider("RollDelay", { Text = "Loop delay", Default = 1, Min = 0.5, Max = 10, Rounding = 1, Suffix = "s" })
local Merging = MergeSub:AddLeftGroupbox("Merging", "combine")
Merging:AddToggle("AutoMerge", { Text = "Auto Merge", Default = false, Tooltip = "Merges 3 of a kind (MergeService.MergeAll)" })
Merging:AddSlider("MergeDelay", { Text = "Loop delay", Default = 1, Min = 0.5, Max = 10, Rounding = 1, Suffix = "s" })
local Buying = BuySub:AddLeftGroupbox("Purchasing", "shopping-cart")
Buying:AddToggle("AutoBuy", { Text = "Auto Buy", Default = false, Tooltip = "Buys pedestal blade cards (BuyOffer + card index)" })
Buying:AddSlider("BuyDelay", { Text = "Loop delay", Default = 1, Min = 0.5, Max = 10, Rounding = 1, Suffix = "s" })
Buying:AddDropdown("BuyRarity", {
Text = "Rarities to buy",
Values = { "Common", "Uncommon", "Rare", "Epic", "Legendary", "Mythic", "Secret" },
Default = { "Common", "Uncommon", "Rare", "Epic", "Legendary", "Mythic", "Secret" },
Multi = true,
})
Buying:AddSlider("BuyMaxPrice", { Text = "Max price", Default = 10000, Min = 0, Max = 100000, Rounding = 0, Prefix = "$" })
local Team = TeamSub:AddLeftGroupbox("Team", "users")
Team:AddToggle("AutoEquip", { Text = "Auto Equip Best Spinner", Default = false, Tooltip = "Equips highest BasePower blades" })
Team:AddSlider("EquipDelay", { Text = "Loop delay", Default = 1, Min = 0.5, Max = 10, Rounding = 1, Suffix = "s" })
Team:AddButton({ Text = "Equip best now", Func = function()
task.spawn(function()
local data = getPlayerData()
if not data then return end
local list = {}
for uuid, info in pairs(data.Blades or {}) do
table.insert(list, { uuid = uuid, power = bladePower(info.Id, info.Level) })
end
table.sort(list, function(a, b) return a.power > b.power end)
local slots = 2
local ok, unlocked = invoke("TeamService", "GetUnlocked")
if ok and tonumber(unlocked) then slots = tonumber(unlocked) end
for i = 1, math.min(slots, #list) do
invoke("TeamService", "SetSlot", i, list[i].uuid)
task.wait(0.2)
end
end)
end })
local Upgrading = UpgradeSub:AddLeftGroupbox("Upgrading", "arrow-big-up")
Upgrading:AddToggle("AutoLuck", { Text = "Auto Upgrade Luck", Default = false, Tooltip = "Upgrades the luck sign (LuckService.Upgrade), stops at max" })
Upgrading:AddSlider("LuckDelay", { Text = "Loop delay", Default = 1, Min = 0.5, Max = 10, Rounding = 1, Suffix = "s" })
end
-- Settings tab: config + anti-AFK (enabled by default)
do
local Safety = Tabs.Settings:AddLeftGroupbox("Safety", "shield")
Safety:AddToggle("AntiAfk", { Text = "Anti-AFK", Default = true, Tooltip = "Disables idle kick connections" })
local Menu = Tabs.Settings:AddLeftGroupbox("Menu", "wrench")
Menu:AddLabel("Menu bind"):AddKeyPicker("MenuKeybind", { Default = "RightShift", NoUI = true, Text = "Menu keybind" })
Menu:AddButton("Unload", function() Library:Unload() end)
Library.ToggleKeybind = Options.MenuKeybind
ThemeManager:SetLibrary(Library)
SaveManager:SetLibrary(Library)
SaveManager:IgnoreThemeSettings()
SaveManager:SetIgnoreIndexes({ "MenuKeybind" })
ThemeManager:SetFolder("hidevin")
SaveManager:SetFolder("hidevin/Spinner Battles")
SaveManager:BuildConfigSection(Tabs.Settings)
ThemeManager:ApplyToTab(Tabs.Settings)
SaveManager:LoadAutoloadConfig()
end
-- Loops (1s interval rule; Library.Unloaded breaks them on unload/reload)
local startClock = os.clock()
task.spawn(function()
while not Library.Unloaded do
if Toggles.AutoRoll and Toggles.AutoRoll.Value then
invoke("RollService", "Summon")
end
task.wait(Options.RollDelay and Options.RollDelay.Value or 1)
end
end)
task.spawn(function()
while not Library.Unloaded do
if Toggles.AutoStart and Toggles.AutoStart.Value then
invoke("BattleService", "Start")
end
task.wait(Options.StartDelay and Options.StartDelay.Value or 1)
end
end)
task.spawn(function()
while not Library.Unloaded do
if Toggles.AutoMerge and Toggles.AutoMerge.Value then
invoke("MergeService", "MergeAll")
end
task.wait(Options.MergeDelay and Options.MergeDelay.Value or 1)
end
end)
-- Pedestal blade cards: OfferCard1..3, card index == BuyOffer index (verified live)
local function titleCase(s)
s = tostring(s or "")
return (s:lower():gsub("^%l", string.upper))
end
local function readCard(i)
local gui = LocalPlayer.PlayerGui:FindFirstChild("OfferCard" .. i)
if not gui then return nil end
local entry = gui:FindFirstChild("Holder")
if entry then entry = entry:FindFirstChild("Entry") end
if not entry then return nil end
local function textOf(path)
local n = entry:FindFirstChild(path)
if n and n:IsA("TextLabel") then return n.Text end
return ""
end
local actionBtn = entry:FindFirstChild("ActionBtn")
local actionTitle = ""
if actionBtn then
local t = actionBtn:FindFirstChild("Title")
if t and (t:IsA("TextLabel") or t:IsA("TextButton")) then actionTitle = t.Text end
end
local m = actionTitle:match("%$([%d,]+)")
local price = (m and tonumber((m:gsub(",", "")))) or math.huge
return {
name = textOf("Nm"),
rarity = titleCase(textOf("Rar")),
price = price,
sold = actionTitle:find("SOLD") ~= nil,
}
end
local function raritySelected(rarity)
local dd = Options.BuyRarity
if not dd then return true end
local ok, active = pcall(function() return dd:GetActiveValues() end)
if ok and type(active) == "table" then
for _, v in ipairs(active) do
if v == rarity then return true end
end
return false
end
local val = dd.Value
if type(val) == "table" then
if #val > 0 then
for _, v in ipairs(val) do
if v == rarity then return true end
end
return false
end
return val[rarity] == true
end
return true
end
task.spawn(function()
while not Library.Unloaded do
if Toggles.AutoBuy and Toggles.AutoBuy.Value then
local data = getPlayerData()
local coins = data and tonumber(data.Coins) or math.huge
local maxPrice = Options.BuyMaxPrice and tonumber(Options.BuyMaxPrice.Value) or math.huge
for i = 1, 3 do
if Library.Unloaded then break end
if not (Toggles.AutoBuy and Toggles.AutoBuy.Value) then break end
local card = readCard(i)
if card and not card.sold and raritySelected(card.rarity) then
if card.price <= coins and card.price <= maxPrice then
local okBuy, res = invoke("RollService", "BuyOffer", i)
if okBuy and res then
coins -= card.price
task.wait(0.3)
else
task.wait(0.2)
end
end
end
end
end
task.wait(Options.BuyDelay and Options.BuyDelay.Value or 1)
end
end)
task.spawn(function()
while not Library.Unloaded do
if Toggles.AutoLuck and Toggles.AutoLuck.Value then
local ok, st = invoke("LuckService", "GetState")
if ok and type(st) == "table" and not st.Max then
local data = getPlayerData()
local coins = data and tonumber(data.Coins) or 0
if coins >= (tonumber(st.Cost) or 0) then
invoke("LuckService", "Upgrade")
end
end
end
task.wait(Options.LuckDelay and Options.LuckDelay.Value or 1)
end
end)
task.spawn(function()
while not Library.Unloaded do
if Toggles.AutoOrbs and Toggles.AutoOrbs.Value then
local claim = RF("BattleService", "ClaimOrb")
for _, d in ipairs(workspace:GetDescendants()) do
if Library.Unloaded then break end
if not (Toggles.AutoOrbs and Toggles.AutoOrbs.Value) then break end
local det, ref = nil, nil
if d:IsA("ClickDetector") then
local p = d.Parent
local fullname = ""
pcall(function() fullname = d:GetFullName() end)
if fullname:find("Orb") and p and p:IsA("BasePart") then
det, ref = d, p
end
elseif d:IsA("BasePart") and (d.Name == "EnergyOrb" or d.Name:find("Orb")) then
det = d:FindFirstChildOfClass("ClickDetector")
ref = d
end
if det or ref then
if det then pcall(fireclickdetector, det) end
if claim and ref then pcall(function() claim:InvokeServer(ref) end) end
end
end
end
task.wait(Options.OrbDelay and Options.OrbDelay.Value or 1)
end
end)
task.spawn(function()
while not Library.Unloaded do
if Toggles.AutoEquip and Toggles.AutoEquip.Value then
local data = getPlayerData()
if data then
local list = {}
for uuid, info in pairs(data.Blades or {}) do
table.insert(list, { uuid = uuid, power = bladePower(info.Id, info.Level) })
end
table.sort(list, function(a, b) return a.power > b.power end)
local slots = 2
local ok, unlocked = invoke("TeamService", "GetUnlocked")
if ok and tonumber(unlocked) then slots = tonumber(unlocked) end
for i = 1, math.min(slots, #list) do
invoke("TeamService", "SetSlot", i, list[i].uuid)
task.wait(0.2)
end
end
end
task.wait(Options.EquipDelay and Options.EquipDelay.Value or 1)
end
end)
-- Anti-AFK + dashboard status
local function setAntiAfk(on)
if not getconnections then return end
pcall(function()
for _, c in ipairs(getconnections(LocalPlayer.Idled)) do
if on then
if c.Disable then c:Disable() end
else
if c.Enable then c:Enable() end
end
end
end)
end
setAntiAfk(true)
if Toggles.AntiAfk then
Toggles.AntiAfk:OnChanged(function() setAntiAfk(Toggles.AntiAfk.Value) end)
end
task.spawn(function()
while not Library.Unloaded do
local el = math.floor(os.clock() - startClock)
pcall(function()
Options.SessionTime:SetText(string.format("Session: %02d:%02d", math.floor(el / 60), el % 60))
end)
local data = getPlayerData()
if data then
pcall(function()
local blades = 0
for _ in pairs(data.Blades or {}) do blades += 1 end
Options.WalletInfo:SetText("Coins: " .. tostring(data.Coins or 0) .. " | Trophies: " .. tostring(data.Trophies or 0))
Options.TeamInfo:SetText("Blades: " .. blades .. " | Best wave: " .. tostring(data.BestWave or 0))
end)
end
task.wait(1)
end
end)
Library:OnUnload(function()
print("[Spinner Battles] Unloaded")
end)
Library:Notify({ Title = "@hidevin", Description = "Spinner Battles loaded", Time = 3 })
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