Skip to content

Tween

Twill.Tween.Play(gui, { Position = UDim2.fromScale(0.5, 0.5) }, { Time = 0.4 })
local door = Twill.Tween.new(model, { Pivot = openCFrame }, { Time = 1 }, bag)
door:Play()

A tween here is a table, not an Instance. Every tween in the game shares one connection that exists only while something is playing, so a frame costs the writes it makes and nothing else, and a place that tweens nothing pays nothing.

The loop runs on PreRender on a client and on PostSimulation on a server.

TweenService reaches properties. This reaches four things:

Written asMoves
Transparency = 1A property of the instance.
["@Charge"] = 100An attribute, named with a leading @.
Pivot = cframeA PVInstance, through PivotTo.
Scale = 2A Model, through ScaleTo.

Scale resizes a Model only. On any other instance it is that instance’s own property, so Scale on a UIScale or a SpecialMesh moves like Transparency does. A model’s Scale has to end above zero.

Nine types can be moved: number, boolean, Vector2, Vector3, UDim, UDim2, CFrame, Color3, and NumberRange.

A plain table works as a target too, which is what makes a tween testable without a DataModel and what lets you drive a number nothing on screen owns yet.

local counter = { Coins = 0 }
Twill.Tween.Play(counter, { Coins = 500 }, { Time = 2 })

A destination given as an array of two or three values is a curve through control points rather than a straight line.

Twill.Tween.Play(part, {
Position = { finish, controlOne, controlTwo },
}, { Time = 1.5 })

The first entry is where it ends and the rest are leaned towards on the way, a quadratic Bezier with one and a cubic with two. Vector2, Vector3, UDim2 and CFrame can be curved; everything else travels straight.

A Color3 is interpolated through Oklab rather than through raw RGB channels, so a blue reaching a yellow passes through the greens a person expects instead of sagging through grey. Channels outside what a screen shows are brought back to what it does. Nothing is asked of you for this.

Starting a tween takes every property it moves away from whoever held it, and the older tween is cancelled rather than left fighting for the same field.

local slow = Twill.Tween.new(gui, { Position = there }, { Time = 4 })
local fast = Twill.Tween.new(gui, { Position = elsewhere }, { Time = 0.2 })
slow:Play()
fast:Play() -- slow is cancelled, and Position is now fast's

This is per property and per target, so two tweens moving different fields of the same instance never disturb each other.

Tweening an Instance on the server sends every frame of it to every client, and Twill refuses it rather than letting that cost arrive unannounced.

Twill.Tween.Play(part, { Transparency = 1 }, { AllowServer = true })

Tween on the client where you can. Pass AllowServer when the replication is the point, which it is for a door every player has to agree about. The guard is about replication, so tweening a plain table on the server is ordinary and is never refused.

A tween belongs to the bag given as its last argument, and to the framework’s own bag when that is left out, so nothing here is ever left running with no owner.

Twill.Tween.new(gui, { Position = there }, { Time = 1 }, Twill.Scope.Player(player))

A tween whose target instance is destroyed ends itself and reports gone. Tween.Play tidies itself away once it stops, which is what makes it safe to call and forget.

[Server] | [Client]

Builds a tween and leaves it standing, ready to be played.

function Tween.new(
target: Instance | Values,
values: Values,
options: Options?,
owner: Scope.Bag?
): Tween

Parameters

NameTypeDescription
targetInstance | { [string]: any }What holds the values that are to move.
valuesValuesWhat each name should reach. An array of two or three curves it.
optionsOptions?How long it takes and how it is shaped.
ownerScope.Bag?The bag it belongs to. The framework’s own when left out.

Returns

Tween - The tween, not yet playing.

Throws when the target is neither an Instance nor a table, when no values were given, when a name is unknown, unwritable, or given the wrong type, when any part of a value or control point is not finite, when a model’s Scale would end at zero or below, and when a server was asked to tween an Instance without AllowServer.

Every destination is checked and every write is tried once at the starting value while the tween is built, so a tween that would fail fails here rather than mid-flight.

[Server] | [Client]

Builds a tween, plays it at once, and tidies it away when it stops.

function Tween.Play(
target: Instance | Values,
values: Values,
options: Options?,
owner: Scope.Bag?
): Tween

Returns

Tween - The tween, already playing, and gone once it is over.

Takes and refuses exactly what Tween.new does.

export type Options = {
Time: number?,
EasingStyle: (string | Easing.Curve)?,
EasingDirection: string?,
DelayTime: number?,
RepeatCount: number?,
Reverses: boolean?,
FPS: number?,
AllowServer: boolean?,
}
FieldDefaultMeaning
Time1Seconds one round takes. Finite and above zero.
EasingStyle"Quad"A style name, or a curve of your own taking and returning a number.
EasingDirection"Out"In, Out, InOut, or OutIn.
DelayTime0Seconds to wait before the first move. Finite, zero or more.
RepeatCount0Extra rounds after the first. Below zero repeats forever. Finite.
ReversesfalseWhether a round travels back before it counts as done.
FPSevery frameWrite no more often than this many times a second. Finite and above zero.
AllowServerfalseWhether an Instance may be tweened on a server.

Eleven easing styles are available: Linear, Quad, Cubic, Quart, Quint, Sine, Exponential, Circular, Back, Elastic, and Bounce. Each is written once as its In curve and the other three directions are derived from it, so a family is right or wrong in one place rather than in four.

A curve of your own is sampled at five points when it is given, and refused there if any of them is not a finite number, rather than failing mid-flight. A curve may leave the range zero to one on the way, which is what Back and Elastic do.

Twill.Tween.Play(gui, { Position = there }, {
EasingStyle = function(alpha: number)
return alpha * alpha
end,
})

FPS is for the deliberately stepped look, a health bar ticking rather than sliding, and for cutting the cost of a tween nobody is looking closely at. The final write always lands whatever the rate.

[Server] | [Client]

Starts the tween, picking up where a pause left it, and starting over after an arrival.

function Tween:Play(): Tween

Returns

Tween - The tween itself, so calls chain.

Throws when the tween has been destroyed. Playing one that is already playing does nothing.

[Server] | [Client]

Holds the tween where it is, so playing again carries on from there.

function Tween:Pause(): Tween

Stopped does not fire, since the caller already knows.

[Server] | [Client]

Stops the tween and forgets how far it got, leaving the values where they are.

function Tween:Cancel(): Tween

Stopped fires with cancelled.

[Server] | [Client]

Stops the tween and puts every value back where it started.

function Tween:Reset(): Tween

Stopped fires with cancelled.

[Server] | [Client]

Answers whether the tween is on the loop right now.

function Tween:IsPlaying(): boolean

[Server] | [Client]

Ends the tween for good and lets go of everything it held.

function Tween:Destroy()

Does nothing the second time.

[Server] | [Client]

A Signal firing when the tween reaches the far end of its last round. It does not fire for a cancel, a pause, or a failure.

[Server] | [Client]

A Signal carrying why a tween stopped when the stop was not the caller’s doing.

ReasonMeans
cancelledCancel or Reset ran, or a newer tween claimed a property.
goneThe target instance left the world.
faultedA write failed, and the tween was stopped so the rest keep running.

A fault is also written to the log at Error under Twill.Tween, carrying what went wrong.

[Server] | [Client]

Returns how many tweens are playing right now across the whole game.

function Tween.Active(): number

This is the number to watch when you suspect something is being left running.

[Server] | [Client]

Answers whether a value is one of these tweens.

function Tween.Is(value: any): boolean

It does not replicate. A tween played on one client is that client’s, and making every player agree about a moving door is a job for Net and Replication, which do it by sending the decision rather than the frames.

It does not sequence. Chaining is Completed:Connect, and that stays explicit rather than becoming a timeline format to learn.

LimitValue
Control points on a curve1 or 2
Easing styles11
Types that can be moved9
Types that can be curved4
Samples taken from a custom curve5