How to Make Objects Spin in Roblox Studio (Copy & Paste Script)

This guide gives you a geometric spinner that rotates a Part or a full Model around its
bounding-box center (not center-of-mass). It works even when anchored, uses CFrame/PivotTo,
and runs smoothly each frame via RunService.Heartbeat.
Geometric Spinner Script (Parts & Models)
Put this Script inside any Part or Model you want to spin. It rotates around the geometric center and works even when anchored.
-- Script inside the Part or Model you want to spin.
-- Spins around the GEOMETRIC CENTER (bounding-box center), not COM.
-- Uses CFrame/PivotTo, so works even if anchored.
local rps = 0.25 -- rotations per second
local axis = Vector3.new(0, 1, 0) -- world axis to spin around (Y = up)
local RunService = game:GetService("RunService")
local function anchorDescendants(model, anchored)
for _, inst in ipairs(model:GetDescendants()) do
if inst:IsA("BasePart") then
inst.Anchored = anchored
end
end
end
local owner = script.Parent
-- CASE 1: Single Part
if owner:IsA("BasePart") then
owner.Anchored = true -- anchor for visual spinning
local omega = rps * 2 * math.pi
local last = tick()
while owner.Parent do
local now = tick()
local dt = now - last
last = now
-- rotate around world axis, keeping same position
local rot = CFrame.fromAxisAngle(axis.Unit, omega * dt)
owner.CFrame = CFrame.new(owner.Position) * rot * owner.CFrame.Rotation
RunService.Heartbeat:Wait()
end
return
end
-- CASE 2: Model
if owner:IsA("Model") then
local anyPart = owner:FindFirstChildWhichIsA("BasePart", true)
if not anyPart then
warn("[Spinner] Model has no parts:", owner:GetFullName())
return
end
-- Anchor all parts so physics won't fight the visual spin
anchorDescendants(owner, true)
local bboxCF, _ = owner:GetBoundingBox()
local centerCF = CFrame.new(bboxCF.Position) -- translation only
-- Remember model's current pivot relative to center
local offset = centerCF:ToObjectSpace(owner:GetPivot())
local omega = rps * 2 * math.pi
local last = tick()
while owner.Parent do
local now = tick()
local dt = now - last
last = now
local rot = CFrame.fromAxisAngle(axis.Unit, omega * dt)
owner:PivotTo(centerCF * rot * offset)
RunService.Heartbeat:Wait()
end
return
end
warn("[Spinner] Parent must be a BasePart or Model, got:", owner.ClassName)
How It Works (Explained)
1) Rotations Per Second (rps)
rps = 0.25 means one quarter turn per second (full rotation every 4 seconds). We convert to radians/sec with omega = rps * 2π.
2) Case 1: Single Part
A Part’s CFrame.Position is already its geometric center. Each frame we compute dt, build a rotation with CFrame.fromAxisAngle, and reapply position + orientation so it spins in place.
3) Case 2: Model
Models don’t have a single CFrame, so we take the bounding-box center via GetBoundingBox(), store the current pivot offset, and on each frame call PivotTo(center * rotation * offset) so it spins exactly around that center.
4) Anchoring
We anchor Parts (or all descendants for Models) so physics doesn’t fight the manual rotation. This is ideal for pickups, coins, spinning props, etc.
5) Heartbeat Loop
The rotation runs on RunService.Heartbeat for smooth, frame-by-frame updates at the desired speed.
How to Use It (Step-by-Step)
For a Single Part
- Insert a Part (e.g., coin or cube) into Workspace.
- Set Anchored = true.
- Insert a Script inside the Part and paste the code.
- Press Play → it spins forever around its center.
For a Model
- Group your pieces into a Model.
- Insert a Script in the Model and paste the code.
- Press Play → it spins around its bounding-box center.
Customizing Speed & Axis
- Speed: set rps to 1 (fast), 0.1 (slow), etc.
- Axis: Vector3.new(0,1,0) spins around Y (up). Try Vector3.new(1,0,0) for X or Vector3.new(0,0,1) for Z.
- Start/Stop: gate the loop with a BoolValue or custom event to toggle spinning at runtime.
Related Roblox Studio guides

