Math and Space
Spring
Physically based springs for numbers, Vector2, Vector3 and CFrame. Natural motion for cameras, UI and effects without tweens.
Getting it
local Spring = Engine:GetPackage("Spring")Overview
A spring moves its Position towards its Target like a damped spring would: it accelerates, slows down near the target and, depending on the damper, may overshoot and wobble. Change the target at any time and the spring reacts smoothly from wherever it is, keeping its current velocity. That makes springs ideal for things that follow input, such as cameras, cursors, hover effects or a health bar.
Springs are evaluated analytically from the time since the last change. There is no per-frame update to call; reading Position at any moment gives the exact value.
local Spring = Engine:GetPackage("Spring")
local scale = Spring.new(0, { speed = 18, damper = 0.6 })
local unbind = scale:Bind(panel.UIScale, "Scale")
openButton.Activated:Connect(function()
scale.Target = 1
end)
closeButton.Activated:Connect(function()
scale.Target = 0
end)Speed and damper
| Setting | Effect |
|---|---|
speed | How fast the spring moves. Higher is snappier. Must be positive. |
damper | How quickly motion dies out. 1 reaches the target without overshooting (critically damped). Below 1 it overshoots and bounces; 0 never stops. Above 1 it creeps in slowly. |
Constructors
new
Spring.new(initial: SpringValue, config: { speed: number?, damper: number? }?, clock: (() -> number)?): SpringA spring at rest at initial. The type of initial (number, Vector2, Vector3 or CFrame) fixes the spring's Kind. Speed and damper default to the configuration values.
Presets
Spring.FromPreset(name: string, initial: SpringValue, clock?): Spring
Spring.Gentle(initial), Spring.Wobbly(initial), Spring.Stiff(initial), Spring.Slow(initial), Spring.Bouncy(initial)Ready-made speed and damper pairs. Their values come from the configuration.
| Function | Description |
|---|---|
Spring.RegisterPreset(name, speed, damper) | Adds your own preset, which also becomes a shortcut such as Spring.Snappy(initial). |
Spring.GetPresetInfo(name): (speed, damper) | Reads a preset. |
Spring.GetPresetNames(): { string } | Every preset name. |
Spring.IsSpringValue(value): boolean | Whether a value can be sprung. |
Spring members
| Member | Description |
|---|---|
Target | Where the spring is heading. Set it to move the spring. |
Position | Read-only. The current value. |
Velocity | Read-only. The current rate of change (a Vector3 of linear velocity for CFrame springs). |
Speed, Damper | Can be changed at any time. |
Kind | Read-only: "number", "Vector2", "Vector3" or "CFrame". |
Settled: Signal | Fires when the spring comes to rest at its target. Rescheduled whenever the spring changes. |
Impulse
spring:Impulse(velocity: SpringValue)Adds velocity, like hitting the spring. For CFrame springs pass a Vector3 (linear velocity only).
-- Camera shake on landing
cameraOffset:Impulse(Vector3.new(0, -12, 0))SkipToTarget / Stop
spring:SkipToTarget()
spring:Stop()SkipToTarget jumps straight to the target and stops. Stop freezes the spring where it is right now by making its current position the new target.
Bind
spring:Bind(instance: Instance, property: string): () -> ()Writes Position to instance[property] every frame. Returns a function that stops the binding; it also stops when the instance is destroyed.
Extrapolate
spring:Extrapolate(seconds: number): SpringValueWhere the spring will be after seconds if nothing changes.
IsSettled / TimeToSettle
spring:IsSettled(threshold: number?): boolean
spring:TimeToSettle(threshold: number?): numberWhether the distance to the target is below threshold, and how many seconds until it will be.
Clone
spring:Clone(): SpringA new spring with the same state that moves on independently.
Spring groups
Spring.Group(initial: { [string]: SpringValue }, config: { [string]: SpringConfig }?, clock?): SpringGroupSeveral named springs that you drive together, for example position, size and transparency of one frame.
local card = Spring.Group({
Position = UDim2.fromScale(0.5, 0.6).Y.Scale,
Transparency = 1,
})
card:SetTarget({ Position = 0.5, Transparency = 0 })| Method | Description |
|---|---|
:Get(name): Spring | One spring of the group. |
:Names(): { string } | Every spring name. |
:SetTarget(targets) | Set several targets at once. |
:Impulse(impulses) | Impulse several springs. |
:SkipToTarget(names?), :Stop(names?) | For all springs, or only the named ones. |
:IsSettled(threshold?), :TimeToSettle(threshold?) | For the whole group. |
:Bind(instance, propertyMap) | Bind springs to properties: { [springName] = propertyName }. Returns an unbind function. |
:Extrapolate(seconds) | Future value of every spring. |
:Clone() | Independent copy of the group. |
Configuration
DefaultConfiguration/Packages/Spring15 settings| Setting | Default | What it does |
|---|---|---|
| DefaultSpeed | 10 | Speed Spring.new() uses when config.speed is omitted; settles in a few tenths of a second. |
| DefaultDamper | 1 | Damper Spring.new() uses when config.damper is omitted; 1 is critically damped (no overshoot). |
| DefaultSettleThreshold | 0.01 | Position error under which :IsSettled()/:TimeToSettle() count the spring as settled. |
| SettleSearchSamples | 200 | Samples :TimeToSettle() steps through while searching. |
| SettleSearchMaxSeconds | 30 | Furthest time :TimeToSettle() searches before giving up. |
| PresetGentleSpeed | 6 | Speed of the Spring.Gentle preset. |
| PresetGentleDamper | 1 | Damper of the Spring.Gentle preset. |
| PresetWobblySpeed | 12 | Speed of the Spring.Wobbly preset. |
| PresetWobblyDamper | 0.3 | Damper of the Spring.Wobbly preset. |
| PresetStiffSpeed | 20 | Speed of the Spring.Stiff preset. |
| PresetStiffDamper | 1 | Damper of the Spring.Stiff preset. |
| PresetSlowSpeed | 2 | Speed of the Spring.Slow preset. |
| PresetSlowDamper | 1 | Damper of the Spring.Slow preset. |
| PresetBouncySpeed | 10 | Speed of the Spring.Bouncy preset. |
| PresetBouncyDamper | 0.15 | Damper of the Spring.Bouncy preset. |
Types
export type SpringValue = number | Vector2 | Vector3 | CFrame
export type SpringConfig = { speed: number?, damper: number? }
export type Spring
export type SpringGroup