Animate parts and UI with TweenService instead of teleporting them, and feel the difference polish makes.
Teleporting a part with part.Position = newPos snaps it — instant, harsh, and cheap-feeling. Games that feel good move things smoothly. That's tweening: animating a value from what it is to what you want it to be, over time.
local TweenService = game:GetService("TweenService")
local coin = workspace.Coin
local info = TweenInfo.new(0.5) -- how long the tween takes, in seconds
local goals = { Size = Vector3.new(2, 2, 2) } -- where we're going
local tween = TweenService:Create(coin, info, goals)
tween:Play()
Three pieces:
TweenService:Create(object, info, goals) — builds the animation; :Play() runs it.The coin smoothly grows from its current size to 2×2×2 over half a second. No snapping.
What is the goal table in TweenService:Create for?
TweenInfo.new(0.5) is a linear slide — robotic. Add an easing style and motion gets character:
local info = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
Quad, Out — starts fast, eases into the goal (the classic, feels natural).Bounce — overshoots and bounces at the end.Elastic — rubber-band wobble.Matching: a coin pickup bounces with Bounce, a door slides with Quad, Out, a boss health bar drains with Quad, In. Easing is where the polish lives.
For a gentle up-down bob, add the loop arguments: TweenInfo.new(1, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut, 0, true) — repeat count 0 means forever, and true alternates direction.
To make a tween bounce at the end instead of sliding, you change the style in TweenInfo.
Moving a rotated part with Position works, but the standard way is CFrame — it carries rotation too:
local goals = {
CFrame = coin.CFrame + Vector3.new(0, 5, 0), -- 5 studs up
}
coin.CFrame + Vector3.new(...) means "wherever you are, add this offset." You'll tween CFrame for world objects (it handles rotation) and Position/Size for GUI and simple cases.
Why tween CFrame instead of Position for world objects?
The same service animates GUI elements:
local shopPanel = player.PlayerGui:WaitForChild("ShopPanel")
local goals = {
Position = UDim2.new(0.5, 0, 0.5, 0), -- slide to center
}
local tween = TweenService:Create(shopPanel, TweenInfo.new(0.4, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), goals)
tween:Play()
A shop panel that slides out instead of teleporting is a different-feeling game for the same five lines. This is how you'll open and close the upgrade shop in the final project.
A coin pops bigger when clicked. Write the Play line that actually runs the tween you created.
local pop = TweenService:Create(coin, popInfo, popGoals)
-- run the tween
TweenService:Create builds the animation but does nothing until :Play(). The classic silent no-op.Next section: publishing — getting this into the hands of real players.