#Animation

Vision animates through the scope, not the declaration. Every Spring* call returns a Linker you can wait on or cancel.

They are tween-driven: you pass a TweenInfo, and the curve comes from TweenService:GetValue. The shape is not an imitation of TweenService, it is TweenService.

#Animating a value

SpringEvent drives names you declared with event. Every callback bound to those values runs each frame, so the instances update themselves.

local Interface = Scope:Capture({
    ClassName = "Frame",
    mount(PlayerGui),

    event("Fill", 0.2, function(self, _, Value)
        self.Size = UDim2.fromScale(Value, 1)
    end),
})

Interface:Mount()

Scope:SpringEvent(
    TweenInfo.new(0.6, Enum.EasingStyle.Back, Enum.EasingDirection.Out),
    Interface,
    { Fill = 0.8 }
)

Because it writes through the value, anything merged onto Fill animates too - a bar and its percentage readout stay in step without extra work. Add more names to the table and they all move on one link:

Scope:SpringEvent(TweenInfo.new(0.6), Interface, {
    Fill = 0.8,
    Tint = Color3.fromRGB(88, 101, 242),
})

Pass a list of Visions instead of one and every one of them animates from the same call.

#Animating properties

SpringInstance skips the Vision and drives properties directly.

Scope:SpringInstance(TweenInfo.new(0.18), Button, {
    BackgroundColor3 = Color3.fromRGB(120, 132, 255),
})

#Animating anything else

SpringFunction hands each step to you, with the frame delta.

Scope:SpringFunction(TweenInfo.new(0.7), function(Value, DeltaTime)
    Accent.Rotation = Value
end, 0, 180)

#Waiting

Await yields until the link is done, which makes sequences read top to bottom.

task.spawn(function()
    Scope:SpringInstance(Quick, Panel, { Size = Big }):Await()
    Scope:SpringInstance(Settle, Panel, { Size = Normal })
end)

#Interrupting

Starting a spring on something already animating cancels the old one first.

Button.MouseEnter:Connect(function()
    Scope:SpringInstance(Fade, Button, { BackgroundColor3 = Hover })
end)

Button.MouseLeave:Connect(function()
    Scope:SpringInstance(Fade, Button, { BackgroundColor3 = Idle })
end)

A fast mouse cannot leave two tweens fighting over the same property. This works per claim - a Vision and value name, or an instance and property name.

A tween has no momentum

An interrupted tween restarts from the current value at zero velocity, so it stops dead before accelerating again. That is inherent to a fixed duration and a curve. If you need motion that flows through an interruption, you want a physics spring - see the comparison.

#Overshoot

Back and Elastic return alpha outside 0..1, and Vision does not clamp it. Back/Out peaks at 1.100, so a bar tweening to 1.0 scale will run past its track. Aim at 0.8 and let the overshoot land inside.

#Beyond TweenService

Vision animates three types TweenService cannot: NumberSequence, ColorSequence and string.

Scope:SpringEvent(TweenInfo.new(0.45), Interface, { Status = "Ready" })

Strings type out on UTF-8 boundaries. Sequences interpolate keypoint by keypoint and never insert or remove a waypoint.

#Cleaning up

Links are owned by the scope. Scope:Release cancels everything, and Interface:Cleanup cancels whatever was driving that tree.

#Done

That is the whole library. The API reference has the details.