A pooled, easing-aware tween system you can use to animate UI panels, ease object movement, sequence multi-step choreography, and produce juice effects with zero per-frame allocation after warm-up.
Summary
The Scylla tween utilities animate any numeric value over time with easing, looping, sequencing, and zero per-frame allocation. You point a tween at a value, say where it should end up and how long it should take, and it eases the value across that span, whether the value is a float, a vector, a color, or a rotation. A fluent chain sets the rest: the easing curve, a start delay, loop counts, per-tween time scaling, and callbacks along the way. ScyllaTween is the single entry point that builds them, and the instances it hands back are pooled, so hundreds of tweens running at once settle into zero garbage once the pool has warmed up.
A tween can be driven two ways. Most of the time you hand it to the framework: call PlayManaged() and it ticks itself every frame until it finishes. When that is the wrong fit, in a test, an editor preview, or a paused game whose menus still need to animate, you drive the tween by hand and advance it yourself with Update(dt). Both paths run the same tween; only the clock differs.
For anything more than a single motion, TweenSequence chains tweens into choreography. You append a tween to run after the previous one, join it to run alongside, or drop a delay or a callback between steps, and the whole multi-stage animation reads as one declarative block, carrying the same easing, looping, and callback setters as a lone tween. On top of that sit convenience extensions for the Unity types you actually animate, so a panel fade, an anchored-position slide, a sprite color flash, a material property sweep, or an audio fade becomes one call on the object itself rather than a hand-built tween. Shake, punch, and look-at helpers cover the common juice effects.
Procedural animation is where a game polishes itself: UI fades, camera moves, hit reactions, score popups, and so on. The tween utilities take care of the fiddly parts that keep those animations robust, recycling instances so they never allocate, ticking them each frame, and quietly dropping any tween whose target is destroyed mid-animation so it never reaches for a dead object. You pick the method, chain a few setters, and call PlayManaged(). The framework owns the rest.
Use the tween utilities for:
- UI fade and slide animations:
canvasGroup.TweenFade(0.8f, 0.3f),rectTransform.TweenAnchoredPosition(...). - Camera transitions, look-at, and follow easing.
- Damage flash, hit reaction, and on-screen feedback:
spriteRenderer.TweenColor(Color.red, 0.1f)plus anOnCompletethat reverts. - Procedural shake and punch effects for impact feedback:
TweenShakePosition,TweenPunchScale. - Score popups, gain/loss number animations, and any “value increments toward a target” feel.
- Choreographed multi-stage animations via
TweenSequence(move + rotate + scale in order, or run in parallel viaJoin). - Material property tweens for shader-driven effects (mask fade, displacement, color cycling).
- Audio fade-in and fade-out, fade-out-and-stop, pitch sweep, and spatial-blend ramping.
- Slow-motion ramps and time-scale effects via
SetTimeScaleper tween orSetGlobalTimeScalefor everything.
Features
ScyllaTweenfacade. Static class withTo<T>,From<T>,Value<T>for the six supported value types,Sequence()for choreography, plus bulk control (KillAll,PauseAll, …) and global settings (SetGlobalTimeScale,SetDefaultEase,SetDefaultDuration).- Six built-in tween value types.
TweenFloat,TweenVector2,TweenVector3,TweenVector4,TweenColor,TweenQuaternion. Plus a genericTween<T>base for custom value types. - Fluent configuration chain.
SetEase,SetDelay,SetTimeScale,SetLoops, plus seven lifecycle callbacks (OnStart,OnUpdate,OnComplete,OnKill,OnLoopComplete,OnPause,OnResume). You can build a complete animation in one chained expression. - Comprehensive easing.
EaseTypecovers Linear, Quad/Cubic/Quart/Quint, Sine, Expo, Circ, Back, Elastic, Bounce inIn/Out/InOutflavors.Ease.Evaluate(EaseType, t)is callable standalone when only the curve shape is needed. - Pooled allocator.
TweenPoolrecycles instances afterKillor natural completion. A sustained workload (hundreds of simultaneous tweens) generates zero garbage after the warm-up phase;ScyllaTween.Prewarm(count)warms the pool during loading. - Managed and manual driving modes.
.PlayManaged()ticks the tween throughTweenManagerevery frame automatically; manual tweens are ticked by the caller viatween.Update(dt)for tests, editor previews, or paused-game animations. TweenSequencechoreography.Append,Join,Insert,Prepend,AppendInterval,InsertCallback. Multi-stage and parallel composition reads as one declarative block; nest sequences by appending another sequence.- Looping with three modes.
LoopType.Restartjumps back to the start each loop;Yoyoreverses direction at each end;Incrementaladds the delta to the start each loop (useful for “always move +1 unit” loops). - Six Unity-type extension classes.
TweenTransformExtensions,TweenRectTransformExtensions,TweenCanvasGroupExtensions,TweenSpriteRendererExtensions,TweenMaterialExtensions,TweenAudioSourceExtensions. Convenience helpers likeTweenPosition,TweenAnchoredPosition,TweenFade,TweenColor,TweenVolume, plus shake and punch effects. - Destroyed-target detection. Tweens that animate a Unity object detect when the target is destroyed mid-animation and clean up automatically. No “tween ran on a dead reference” exceptions.
- Per-tween and global time scale.
tween.SetTimeScale(0.5f)slows one animation;ScyllaTween.SetGlobalTimeScale(0.25f)slows everything. The right primitive for slow-motion ramps, pause overlays, and time-bending gameplay. - Structured error contract.
TweenExceptioncarries aTweenErrorCodeso error handlers branch on a stable enum rather than parse messages.
Components
The public surface is split across one facade, one interface, one abstract base plus six concrete tween types, one sequence type, two static managers (pool and manager), one ease evaluator, one settings carrier, one exception family, and six Unity-type extension classes. Most of your code will touch only the facade plus the extensions; the lower layers (TweenPool, TweenManager, Ease) are useful for advanced scenarios.
A few terms worth defining if you are new to this area. A tween is a time-bounded interpolation: a value moves from a start to an end over a duration, optionally with an easing curve shaping the motion. Easing is the function applied to the normalized time (t in [0, 1]) before the interpolation, producing accelerate-in (InQuad), decelerate-out (OutQuad), ease-in-out (InOutCubic), bounce, elastic, and so on. A sequence is an ordered list of tweens, callbacks, and intervals composed together as a single coordinated animation. Managed means the framework’s per-frame runner ticks the tween automatically; manual means you tick it via tween.Update(dt). Pooled means instances are reused from a free list rather than allocated per use, so a sustained workload generates zero per-frame garbage.
| Component | Role | Notes |
|---|---|---|
ScyllaTween | Static facade. Entry point for every tween construction and bulk operation | To<T>, From<T>, Value<T> for the six supported types (float, Vector2, Vector3, Vector4, Color, Quaternion); Sequence() for choreography; Update, Initialize, Prewarm; bulk control (KillAll, PauseAll, etc.); global settings (SetGlobalTimeScale, SetDefaultEase, SetDefaultDuration). |
ITween | Interface implemented by every tween and sequence | Common surface for lifecycle (Play, Pause, Kill, Restart, Complete, Rewind, Update) and configuration (SetEase, SetDelay, SetLoops, callbacks). Use as the declared type when storing a tween for later interaction. |
TweenBase | Abstract base for every concrete tween | Implements ITween. Holds the timing, easing, looping, and callback state. Inherited by TweenFloat, TweenVector2/3/4, TweenColor, TweenQuaternion, and the generic Tween<T>. |
Tween<T> and the six concrete types | Per-type tween implementations | TweenFloat, TweenVector2, TweenVector3, TweenVector4, TweenColor, TweenQuaternion. Created via ScyllaTween.To/From/Value or pulled directly from TweenPool.Get*(). Tween<T> is the generic base for custom value types. |
TweenSequence | Composite of tweens, callbacks, and intervals | Built via Append, Join, Insert, Prepend, plus AppendCallback, AppendInterval, PrependInterval, InsertCallback. Same lifecycle surface as plain tweens; nests via Append of another sequence. |
TweenManager | Static per-frame runner for managed tweens | Auto-ticked by the framework. Public surface: ActiveTweenCount, Register / Unregister, KillAll, PauseAll, ResumeAll, target-based queries (GetTweensByTarget, HasTweens, KillTweensByTarget). Rarely invoked directly; ScyllaTween is the friendlier wrapper. |
TweenPool | Static pool of reusable tween instances | Per-type Get* and Release methods. Auto-initialized on first use; explicit Initialize(capacity, maxSize) and Prewarm(count) for tuning. Pool counts queryable per type. |
Ease / EaseType / LoopType / TweenState | Easing functions and small enums | Ease.Evaluate(EaseType, t) and Ease.GetFunction(EaseType) evaluate a curve standalone; EaseType enumerates 33 curves plus Custom; LoopType is Restart / Yoyo / Incremental; TweenState reports the current lifecycle stage. |
TweenSettings | Global defaults: ease, duration, auto-kill, pool capacity | Set via ScyllaTween.SetDefaultEase, SetDefaultDuration, SetGlobalTimeScale, ResetSettings. Read via the corresponding properties. Pool sizing through ScyllaTween.Initialize(poolCapacity, poolMaxSize). |
TweenException / TweenErrorCode | Typed exception family | Thrown when an operation fails (invalid duration, killed target, etc.). ErrorCode lets a catch block branch on the failure mode without parsing the message. |
TweenID | Lightweight stable identifier for an active tween | Returned by tween.ID. Pass to ScyllaTween.GetTween(id) to recover the tween after PlayManaged(); useful when you don’t want to hold the reference yourself. |
Tween*Extensions (six classes) | Unity-type convenience methods | TweenTransformExtensions (position, rotation, scale, shake, punch, look-at), TweenRectTransformExtensions (anchored position, size, pivot, anchors), TweenCanvasGroupExtensions (alpha, fade in/out), TweenSpriteRendererExtensions (color, alpha, fade), TweenMaterialExtensions (color, alpha, float, vector, texture offset/scale by property name or ID), TweenAudioSourceExtensions (volume, pitch, spatial blend, pan). |
Recipes
These recipes cover every public surface in the tween subsystem. Each one is a self-contained answer to a single game-development problem, so you can jump straight to the one that matches what you are building. If you are new to the API, start with the pool warm-up recipe; the rest assume the pool is ready and a tween is already running.
Prewarm the pool and avoid GC spikes on wave clears
Problem. You’re building a wave-based arena game and every time a wave clears the screen a dozen enemies die at once, their health bars fade, their score numbers pop, and a victory flourish plays. If you have not warmed the tween pool before that moment, the first batch of tweens allocates fresh instances and you get a visible GC spike right when the action is at its most visually busy.
Solution. Call ScyllaTween.Initialize once at startup with a pool capacity tuned for your project, then prewarm during the loading screen so the first burst of gameplay tweens is served from the pool with no allocation. The framework drives ScyllaTween.Update automatically every frame; you only need to call it manually in tests or custom run loops.
using Scylla.Core.Util.Tween;
/* Default initialization: pool capacity 64, max size 500. Fine for
* most prototypes. Re-initializing replaces the existing pool and
* releases pooled instances back to the GC. */
ScyllaTween.Initialize();
/* For a heavier project where dozens of tweens fire simultaneously
* (boss death, wave clear, full-screen transition). */
ScyllaTween.Initialize(poolCapacity: 256, poolMaxSize: 2048);
/* Pre-allocate 128 of each tween type during the loading screen so
* the first wave-clear burst produces zero GC. Without prewarm, the
* first To() of each type allocates a fresh instance. */
ScyllaTween.Prewarm(count: 128);
/* The framework drives Update automatically each frame. Call manually
* only in tests or in a custom game loop where you control the tick. */
ScyllaTween.Update(deltaTime: 1f / 60f);
/* Inspect active count for debug overlays or the performance monitor. */
int active = ScyllaTween.ActiveTweenCount;
Log.Info($"{active} active tweens", LogCategory.Core);
Animate a UI panel fade or object property
Problem. You want the inventory panel to fade in when the player opens it, or an enemy ship to slide into position over 1.5 seconds using a smooth deceleration curve. These are the two most common tween shapes in any game: “animate this Unity property to a new value” (To) and “animate it from an explicit starting value down to where it is now” (From). You’ll also occasionally need the bare Value form when there is no Unity property to bind and you’re driving something like a score counter label directly.
Solution. Every tween starts from one of three factories. All six concrete types (TweenFloat, TweenVector2, TweenVector3, TweenVector4, TweenColor, TweenQuaternion) follow the same shape. Construct, chain your setters, then call PlayManaged() to hand the tween to the framework.
/* Float tween: animate any float-returning getter to a target value.
* The setter is called every frame with the current interpolated value. */
TweenFloat fade = ScyllaTween.To(
getter: () => canvasGroup.alpha,
setter: value => canvasGroup.alpha = value,
endValue: 0f,
duration: 0.5f
);
/* Vector3 tween: same shape with a Vector3 getter/setter.
* Moves an enemy ship to its patrol position over 1.5 seconds. */
TweenVector3 move = ScyllaTween.To(
getter: () => transform.position,
setter: v => transform.position = v,
endValue: new Vector3(10f, 0f, 0f),
duration: 1.5f
);
/* Color, Vector2, Vector4, Quaternion: all follow the same shape. */
TweenColor flash = ScyllaTween.To(
getter: () => renderer.color,
setter: c => renderer.color = c,
endValue: Color.red,
duration: 0.1f
);
TweenQuaternion turn = ScyllaTween.To(
getter: () => transform.rotation,
setter: q => transform.rotation = q,
endValue: Quaternion.Euler(0f, 90f, 0f),
duration: 0.4f
);
/* From: animate the value from an explicit start down to whatever
* the getter returns at construction time. Good for spawn-in effects
* where the object starts tiny and scales up to its real size. */
TweenVector3 popIn = ScyllaTween.From(
getter: () => transform.localScale,
setter: v => transform.localScale = v,
fromValue: Vector3.zero,
duration: 0.3f
);
/* Value: explicit from/to with a single update callback. The right
* shape when there is no Unity property to bind, such as a score
* counter that needs to count up from 0 to the final tally. */
TweenFloat counter = ScyllaTween.Value(
from: 0f,
to: 100f,
duration: 1f,
onUpdate: v => uiLabel.text = ((int)v).ToString()
);
/* Default fluent chain: SetEase, SetDelay, OnComplete, then PlayManaged.
* The OnComplete callback hides the panel after the fade finishes. */
fade.SetEase(EaseType.OutQuad)
.SetDelay(0.1f)
.OnComplete(() => canvasGroup.gameObject.SetActive(false))
.PlayManaged();
Choose an easing curve that matches the feel you want
Problem. There is a precise difference between motion that feels mechanical (linear interpolation, hard cuts) and motion that feels alive (eased curves with the right weight), and the difference almost always lives in the choice of easing. You’re polishing a HUD element that slides in from off-screen, and the default Linear ease makes it look like a spreadsheet cell moving. You want it to decelerate into position the way a physical object would.
Solution. Every tween supports SetEase, SetDelay, SetTimeScale, and SetDuration. EaseType enumerates 33 named curves plus Custom; you can also pass a custom Func<float, float> when none of the named curves fit. Ease.Evaluate lets you sample any curve standalone without a tween, which is useful when you are driving custom procedural animation outside the tween pipeline – see Math & Numbers for the underlying interpolation helpers.
/* Set ease by enum value. */
fade.SetEase(EaseType.OutQuad);
fade.SetEase(EaseType.InOutCubic);
fade.SetEase(EaseType.OutElastic); /* overshoot then settle */
fade.SetEase(EaseType.OutBounce); /* bounce in at the end */
/* Set ease via a custom function. The function maps t in [0, 1]
* to the eased value (also typically in [0, 1] but free to overshoot). */
fade.SetEase(t => 1f - Mathf.Pow(1f - t, 5f)); /* OutQuint by hand */
fade.SetEase(t => t * t * (3f - 2f * t)); /* SmoothStep */
/* Delay before the animation starts. Useful for staggered UI reveals
* where each panel waits a bit longer than the previous one. */
ScyllaTween.To(/* ... */).SetDelay(0.25f).PlayManaged();
/* Per-tween time scale: slow down one tween while everything else
* runs at normal speed. Handy for a slow-motion hit-stop on one enemy
* while the background continues at full pace. */
fade.SetTimeScale(0.5f);
/* Override the duration set in the factory call. */
fade.SetDuration(1.2f);
/* Inspect the current playback state. */
EaseType curve = fade.EaseType;
float elapsed = fade.ElapsedTime;
float total = fade.Duration;
float t = fade.Progress; /* 0..1 */
/* Direct ease evaluation when you need the curve shape but not a tween.
* Useful inside an existing Update() that drives several values from
* one shared curve without running a full tween for each. */
float curveValue = Ease.Evaluate(EaseType.InOutCubic, t: 0.5f);
Func<float, float> curveFunc = Ease.GetFunction(EaseType.OutBounce);
float v = curveFunc(0.7f);
Make an effect pulse, ping-pong, or loop forever
Problem. Some animations are not one-shot but cyclical. A glowing rune on a locked door should pulse indefinitely; a boss idle animation bobs up and down on a yoyo; a damage-flash overlay fires twice before clearing. SetLoops and its helpers cover every repeat shape.
Solution. Pass the total loop count (1 plays once, 2 plays twice) and a LoopType to SetLoops. Pass -1 for infinite. SetLoopInfinite and SetPingPong are shorthand for the two most common infinite cases.
/* Loop three times, restarting from the start value each time.
* Good for a damage flash that fires twice before clearing the overlay. */
fade.SetLoops(loops: 3, LoopType.Restart);
/* Ping-pong (Yoyo): loop 2 reverses, loop 3 is forward again.
* The right shape for a boss idle bobbing up and down. */
fade.SetPingPong(loops: 4);
/* Incremental: each loop adds the change to the start, so a tween
* from 0 to 1 across three Incremental loops runs 0 -> 1 -> 2 -> 3.
* Useful for a conveyor belt that always advances by one tile length. */
counter.SetLoops(loops: 3, LoopType.Incremental);
/* Infinite loop. The glowing rune stays pulsing until the door opens. */
glowTween.SetLoopInfinite(LoopType.Yoyo);
/* Or pass -1 directly if you prefer the explicit form. */
glowTween.SetLoops(loops: -1, LoopType.Yoyo);
/* Inspect loop state at runtime. */
int totalLoops = fade.Loops;
int completedLoops = fade.CompletedLoops;
LoopType type = fade.LoopType;
React to animation events: start, update, complete, kill
Problem. You want the inventory panel’s background to become non-interactable only after the fade-out completes, not at the moment you start the fade. Or you want to play a footstep sound exactly when a movement tween starts. Seven callback hooks let you react at every well-defined moment in a tween’s lifecycle.
Solution. OnStart fires once at the first tick. OnUpdate fires every tick. OnComplete fires when the tween finishes naturally. OnKill fires when the tween is killed (whether or not it completed). OnLoopComplete fires at the end of each loop iteration. OnPause / OnResume fire when the running state changes. OnProgress (from TweenExtensions) delivers the normalized progress value to a delegate, useful for driving a UI progress bar in sync with the animation.
ScyllaTween.To(/* ... */)
.OnStart(() => Log.Info("Started", LogCategory.Core))
.OnUpdate(() => Log.Info($"Tick: {fade.Progress:F2}", LogCategory.Core))
.OnComplete(() => Log.Info("Done", LogCategory.Core))
.OnKill(() => Log.Info("Killed (may or may not have completed)", LogCategory.Core))
.OnLoopComplete(() => Log.Info("Loop iteration done", LogCategory.Core))
.OnPause(() => Log.Info("Paused", LogCategory.Core))
.OnResume(() => Log.Info("Resumed", LogCategory.Core))
.PlayManaged();
/* OnProgress: the callback receives the current normalized progress.
* Useful for a load bar or a cast-time indicator that mirrors the tween. */
ScyllaTween.To(/* ... */)
.OnProgress(progress => castBar.SetValue(progress))
.PlayManaged();
/* OnCompleteKill: shorthand for OnComplete + Kill. Useful when the tween
* should release its pooled instance immediately after completing,
* rather than waiting for AutoKill to run on the next manager tick. */
ScyllaTween.To(/* ... */)
.OnCompleteKill(() => OnAnimationFinished())
.PlayManaged();
Pause, restart, and kill tweens from a game event
Problem. Once a tween is running, your game needs to interrupt it: the player opens the pause menu and all animations should freeze, or an entity is destroyed mid-animation and its tweens need to stop immediately, or a cut-scene fires and you want everything to snap to its end state. ITween exposes the full lifecycle surface, and TweenExtensions adds convenience wrappers.
Solution. Play starts a tween in manual mode; PlayManaged registers it with TweenManager for auto-ticking. Pause, Resume, Kill, Restart, Complete, and Rewind all return ITween for chaining. Read IsPlaying, IsComplete, IsPaused, and IsKilled to inspect state. Use TweenID to recover a managed tween by stable handle when you do not want to hold the reference yourself.
/* Play manually: you advance time by calling tween.Update(dt) yourself.
* Useful for tests, editor previews, or paused-game sub-animations. */
var manual = ScyllaTween.To(/* ... */);
manual.Play();
manual.Update(0.016f); /* advance by one 60-fps frame */
/* Play managed: the framework ticks the tween every frame. */
var managed = ScyllaTween.To(/* ... */).PlayManaged();
/* Pause and resume. */
managed.Pause();
managed.Resume();
/* TogglePause: pause if playing, resume if paused. */
managed.TogglePause();
/* Kill: stop the tween. Pass true to snap to the end value first,
* which is what you want when a cut-scene needs instant completion. */
managed.Kill(); /* stop without completing */
managed.Kill(complete: true); /* snap to end value, then stop */
/* Restart: reset to the start state and play from the beginning. */
managed.Restart();
/* Complete: snap to the end value and stop. */
managed.Complete();
/* Rewind: reset to the start state without playing. */
managed.Rewind();
/* PlayWithEase: SetEase + PlayManaged in one call. */
ScyllaTween.To(/* ... */).PlayWithEase(EaseType.OutCubic);
/* PlayDelayed: SetDelay + PlayManaged in one call. */
ScyllaTween.To(/* ... */).PlayDelayed(delay: 0.25f);
/* WaitForCompletion: alias for OnComplete that also kills the tween
* after firing. Use when the next step depends on this one finishing. */
ScyllaTween.To(/* ... */).WaitForCompletion(onComplete: () => NextStep());
/* State inspection. */
bool playing = managed.IsPlaying;
bool done = managed.IsComplete;
bool paused = managed.IsPaused;
bool killed = managed.IsKilled;
float left = managed.GetRemainingTime();
float total = managed.GetTotalDuration();
bool active = managed.IsActive(); /* IsPlaying || IsPaused */
/* SetTarget: attach a target object so KillTweensOf / IsTweening
* can find this tween later by the owning object. */
managed.SetTarget(transform);
/* SetAutoKill(false): keep the tween alive after completion so it
* can be Restart-ed without rebuilding the chain. */
ScyllaTween.To(/* ... */).SetAutoKill(false).PlayManaged();
/* TweenID: stable handle for recovering a tween after PlayManaged. */
TweenID id = managed.ID;
ITween found = ScyllaTween.GetTween(id);
Choreograph a multi-step UI or entity animation
Problem. Anyone who has hand-animated a multi-step UI transition (slide-in, then fade, then a small bounce, then a finishing flourish) knows the value of chaining individual tweens into one coordinated sequence rather than nesting timing callbacks. TweenSequence is the answer: it composes multiple tweens, callbacks, and intervals into one declarative block that you can pause, kill, or restart as a unit.
Solution. Append adds the next item after the previous one finishes; Join runs it in parallel with the previous item; Insert places an item at an absolute time position; Prepend puts an item at the head; AppendCallback / InsertCallback add discrete events; AppendInterval / PrependInterval add empty gaps. The same fluent chain as plain tweens applies to the sequence itself.
/* Sequential: position moves to target, then the object rotates, then scales.
* A classic "unit walks to position and turns to face the enemy" transition. */
var seq = ScyllaTween.Sequence();
seq.Append(transform.TweenPosition(target, 1f).SetEase(EaseType.OutCubic));
seq.Append(transform.TweenRotation(Quaternion.Euler(0f, 180f, 0f), 0.5f));
seq.Append(transform.TweenScale(Vector3.one * 1.5f, 0.3f));
seq.PlayManaged();
/* Parallel: position and rotation run at the same time, then scale runs after.
* Join attaches the rotation to the same start time as the position tween. */
var parallel = ScyllaTween.Sequence();
parallel.Append(transform.TweenPosition(target, 1f));
parallel.Join(transform.TweenRotation(Quaternion.Euler(0f, 180f, 0f), 1f));
parallel.Append(transform.TweenScale(Vector3.one * 1.5f, 0.3f));
parallel.PlayManaged();
/* Insert: place a tween at an absolute time position. Useful for finely
* choreographed effects where a secondary element starts partway through. */
var precise = ScyllaTween.Sequence();
precise.Append(transform.TweenPosition(p1, 1f));
precise.Append(transform.TweenPosition(p2, 1f));
precise.Insert(atPosition: 0.5f, transform.TweenScale(Vector3.one * 1.2f, 0.5f));
precise.PlayManaged();
/* PrependInterval: add a wait at the start before the first item. */
var withIntro = ScyllaTween.Sequence();
withIntro.Append(transform.TweenPosition(p1, 1f));
withIntro.PrependInterval(0.5f); /* half a second of silence before the move */
/* AppendCallback / InsertCallback / AppendInterval for events and waits. */
var choreographed = ScyllaTween.Sequence();
choreographed.Append(transform.TweenPosition(p1, 1f));
choreographed.AppendCallback(() => PlaySoundEffect("step"));
choreographed.AppendInterval(0.25f);
choreographed.Append(transform.TweenPosition(p2, 1f));
choreographed.InsertCallback(atPosition: 1.5f, callback: () => SpawnParticles());
/* Sequences support the same fluent surface as plain tweens. */
choreographed
.SetLoops(loops: 2, LoopType.Yoyo)
.OnComplete(() => Log.Info("Choreography done", LogCategory.Core))
.PlayManaged();
/* Nest a sequence inside another by appending it. */
var outer = ScyllaTween.Sequence();
outer.Append(transform.TweenPosition(p1, 1f));
outer.Append(choreographed); /* the full inner sequence runs here */
outer.PlayManaged();
/* Inspect sequence state. */
int items = choreographed.ItemCount;
float duration = choreographed.Duration;
Animate Transform, UI, sprite, material, and audio in one line
Problem. Most of your tween call sites already hold a Transform, a CanvasGroup, or a SpriteRenderer in a local variable. Writing the getter/setter pair by hand every time gets repetitive quickly. You want the inventory panel to fade in with one line of code, the damage flash to tint the sprite red with one line, and the footstep sound to fade in on spawn with one line.
Solution. Six static extension classes provide the routine convenience methods on Unity types. Every method returns the corresponding tween type so you can chain, add it to a sequence, or store the reference. Use using Scylla.Core.Util.Tween; to pull them in. See UI Layout for complementary layout helpers that work alongside these animation extensions.
using Scylla.Core.Util.Tween;
/* Transform: position, rotation, scale, plus shake/punch/look-at. */
transform.TweenPosition (new Vector3(10f, 0f, 0f), duration: 1f);
transform.TweenLocalPosition (Vector3.zero, duration: 0.5f);
transform.TweenPositionX (5f, 0.5f);
transform.TweenPositionY (3f, 0.5f);
transform.TweenPositionZ (1f, 0.5f);
transform.TweenRotation (Quaternion.Euler(0f, 90f, 0f), 0.5f);
transform.TweenRotation (new Vector3(0f, 90f, 0f), 0.5f); /* Euler overload */
transform.TweenLocalRotation (Quaternion.identity, 0.5f);
transform.TweenScale (Vector3.one * 1.5f, 0.3f);
transform.TweenScale (1.5f, 0.3f); /* uniform scale */
transform.TweenScaleX (2f, 0.3f);
transform.TweenScaleY (2f, 0.3f);
transform.TweenScaleZ (2f, 0.3f);
transform.TweenMoveBy (Vector3.forward * 2f, 0.5f);
transform.TweenPunchScale (Vector3.one * 0.2f, duration: 0.4f);
transform.TweenShakePosition (Vector3.one * 0.1f, duration: 0.3f, vibrato: 10);
transform.TweenLookAt (targetPosition, duration: 0.5f);
transform.TweenLookAt (targetTransform, duration: 0.5f);
/* RectTransform: anchored position, size delta, pivot, anchor min/max. */
rect.TweenAnchoredPosition (new Vector2(100f, 0f), 0.5f);
rect.TweenAnchoredPositionX (50f, 0.3f);
rect.TweenAnchoredPositionY (50f, 0.3f);
rect.TweenAnchoredPosition3D (new Vector3(50f, 0f, 0f), 0.3f);
rect.TweenSizeDelta (new Vector2(200f, 100f), 0.3f);
rect.TweenWidth (200f, 0.3f);
rect.TweenHeight (100f, 0.3f);
rect.TweenPivot (new Vector2(0.5f, 0.5f), 0.3f);
rect.TweenAnchorMin (Vector2.zero, 0.3f);
rect.TweenAnchorMax (Vector2.one, 0.3f);
/* CanvasGroup: alpha, fade in/out, fade with optional interactable toggle. */
canvasGroup.TweenAlpha (0f, 0.3f);
canvasGroup.TweenFadeIn (0.3f);
canvasGroup.TweenFadeOut (0.3f);
canvasGroup.TweenFade (0.8f, 0.3f, setInteractable: true);
/* SpriteRenderer: color, alpha, fade. The damage flash case: tint red,
* then revert in OnComplete. */
spriteRenderer.TweenColor (Color.red, 0.2f);
spriteRenderer.TweenAlpha (0f, 0.5f);
spriteRenderer.TweenFadeIn (0.5f);
spriteRenderer.TweenFadeOut (0.5f);
/* Material: color, float, vector, texture offset/scale by property
* name or pre-resolved property ID. */
material.TweenColor (Color.cyan, 0.5f);
material.TweenColor ("_BaseColor", Color.cyan, 0.5f);
material.TweenColor (Shader.PropertyToID("_BaseColor"), Color.cyan, 0.5f);
material.TweenAlpha (0f, 0.5f);
material.TweenFloat ("_Smoothness", 0.8f, 0.3f);
material.TweenFloat (Shader.PropertyToID("_Smoothness"), 0.8f, 0.3f);
material.TweenVector ("_Param", new Vector4(1f, 0.5f, 0.2f, 1f), 0.3f);
material.TweenTextureOffset (new Vector2(0.5f, 0f), 1f);
material.TweenTextureScale (new Vector2(2f, 2f), 1f);
/* AudioSource: volume, pitch, spatial blend, pan, plus fade helpers. */
audioSource.TweenVolume (0f, 1f);
audioSource.TweenFadeIn (0.5f);
audioSource.TweenFadeOut (0.5f);
audioSource.TweenFadeOutAndStop(0.5f);
audioSource.TweenPitch (1.5f, 0.5f);
audioSource.TweenSpatialBlend (1f, 0.5f);
audioSource.TweenPanStereo (1f, 0.5f);
Freeze all animations on pause and clean up on scene exit
Problem. You wire up a pause menu and open it mid-wave, but the enemy health bars are still animating, the score counter is still ticking, and the slow-motion ramp from the last kill is still running. You need to freeze every active tween when the game pauses, resume them all when it unpauses, and tear down the full set on scene transitions so nothing leaks into the next scene.
Solution. ScyllaTween exposes bulk operations for stopping, pausing, resuming, and completing every active tween. Target-based queries let you scope the operation to a specific object when you need that granularity. Wire the pause events via ScyllaTween.PauseAll / ScyllaTween.ResumeAll; on scene exit call ScyllaTween.Clear.
/* Stop every active tween. Pass true to snap each to its end value
* before stopping, which is what you want on a cut-scene trigger. */
int killed = ScyllaTween.KillAll();
int killedAndComplete = ScyllaTween.KillAll(complete: true);
/* Stop every tween targeting a specific object. Call this in OnDestroy
* so an entity's remaining animations stop immediately rather than
* throwing on the next setter invocation. */
int killedForTarget = ScyllaTween.KillTweensOf(enemyTransform);
int killedAndCompleteForTarget = ScyllaTween.KillTweensOf(enemyTransform, complete: true);
/* Pause / resume every active tween. Wire these to the game's pause events. */
int paused = ScyllaTween.PauseAll();
int resumed = ScyllaTween.ResumeAll();
/* Snap every tween to its end value and stop. */
int finalized = ScyllaTween.CompleteAll();
/* Clear the manager: kills every tween and clears the pool. Call this
* before loading the next scene so no tweens from the current scene
* bleed through. */
ScyllaTween.Clear();
/* Recover a tween by its stable handle. Returns null when the tween
* has been killed, completed, or returned to the pool. */
TweenID id = managed.ID;
ITween found = ScyllaTween.GetTween(id);
/* Check whether any tweens are currently targeting an object. */
bool isMoving = ScyllaTween.IsTweening(transform);
/* Global time scale: slow-motion or fast-forward every tween at once.
* Useful for a slow-motion ramp on boss death without pausing the tick. */
ScyllaTween.SetGlobalTimeScale(0.5f); /* half speed */
float current = ScyllaTween.GlobalTimeScale;
ScyllaTween.SetGlobalTimeScale(1f); /* back to normal */
/* Project-wide defaults for ease and duration. */
ScyllaTween.SetDefaultEase(EaseType.OutCubic);
ScyllaTween.SetDefaultDuration(0.4f);
/* Reset every global setting to its factory default. */
ScyllaTween.ResetSettings();
/* Direct TweenManager access for advanced per-target queries. */
IReadOnlyList<ITween> onTarget = TweenManager.GetTweensByTarget(transform);
bool any = TweenManager.HasTweens(transform);
int n = TweenManager.PauseTweensByTarget(transform);
int m = TweenManager.ResumeTweensByTarget(transform);
Sample an easing curve directly without running a tween
Problem. Sometimes you need the curve shape, not the tween machinery. You have an existing Update method that lerps a camera spring over multiple values from one shared t, and spinning up a separate tween for each property would be overkill. Or you want to preview a curve in an editor tool without instantiating anything.
Solution. Ease is a static utility class for evaluating easing curves outside the tween pipeline. Ease.Evaluate(EaseType, t) gives you a point on any named curve; Ease.GetFunction(EaseType) returns the delegate if you plan to call it many times. Every named variant is also a direct static method (e.g. Ease.OutCubic(t)), so you can call the curve you need without going through the enum. For general interpolation math that does not involve easing, see Math & Numbers.
/* Evaluate any EaseType at a specific t in [0, 1]. */
float curve = Ease.Evaluate(EaseType.OutBounce, t: 0.7f);
/* Retrieve the curve as a delegate for repeated use across many frames. */
Func<float, float> bounceOut = Ease.GetFunction(EaseType.OutBounce);
for (float t = 0f; t <= 1f; t += 0.1f)
{
float y = bounceOut(t);
/* drive a custom lerp, a shader parameter, or a layout value */
}
/* Direct named-method calls. Every In/Out/InOut variant for Sine, Quad,
* Cubic, Quart, Quint, Expo, Circ, Elastic, Back, Bounce, plus Flash. */
float a = Ease.Linear(0.5f);
float b = Ease.InQuad(0.5f);
float c = Ease.OutCubic(0.5f);
float d = Ease.InOutSine(0.5f);
float e = Ease.OutElastic(0.5f);
float f = Ease.OutBounce(0.5f);
Manage the pool directly for advanced factory patterns
Problem. You’re building a custom tween factory for a particle system that emits hundreds of color flashes per second and you want total control over when instances are pulled from the pool and when they are returned. Or you’re writing editor tooling that needs to inspect pool state and pre-populate it with a specific shape before a preview runs.
Solution. TweenPool is public for exactly these advanced cases. The facade calls it internally and covers most projects, but the per-type Get* and Release methods are available when you need to construct and configure a tween below the factory layer. See Pools for the general pooling patterns used elsewhere in the framework.
/* Initialize the pool with a specific capacity. Auto-runs on first use;
* explicit call avoids the first-batch allocation cost in time-sensitive code. */
TweenPool.Initialize(initialCapacity: 64, maxSize: 500);
/* Inspect pool state for diagnostic overlays or editor tooling. */
bool ready = TweenPool.IsInitialized;
int floats = TweenPool.FloatPoolCount;
int vec3s = TweenPool.Vector3PoolCount;
/* Pull an instance directly from the pool, configure it, and return it.
* The Initialize call sets up every field the facade would set. */
TweenFloat raw = TweenPool.GetFloat();
raw.Initialize(
getter: () => canvasGroup.alpha,
setter: v => canvasGroup.alpha = v,
endValue: 0f,
duration: 0.5f,
lerpFunction: TweenLerp.LerpFloat
);
/* Return the instance to the pool when finished. The framework releases
* automatically on Kill / Complete (with AutoKill = true), so manual
* release is rarely needed. */
TweenPool.Release(raw);
/* Get/Release methods exist for each concrete type. */
TweenVector3 v3 = TweenPool.GetVector3();
TweenColor col = TweenPool.GetColor();
TweenQuaternion q = TweenPool.GetQuaternion();
TweenSequence seq = TweenPool.GetSequence();
/* Prewarm and clear. */
TweenPool.Prewarm(count: 32);
TweenPool.Clear();
API Sketch
The public surface is split across the facade, the interface, the abstract base, six concrete tween classes plus the generic Tween<T>, the sequence type, two static managers, the ease utility, the settings carrier, the exception family, six Unity-type extension classes, and the ITween extension class. Most of your code touches ScyllaTween plus the extension classes; the rest is available for advanced scenarios.
namespace Scylla.Core.Util.Tween
{
/* Facade. */
public static class ScyllaTween
{
/* Setup. */
public static void Initialize();
public static void Initialize(int poolCapacity, int poolMaxSize);
public static void Prewarm(int count);
public static void Update(float deltaTime);
/* Factories. To = animate to endValue; From = animate from fromValue; Value = explicit from/to. */
public static TweenFloat To(Func<float> getter, Action<float> setter, float endValue, float duration);
public static TweenVector2 To(Func<Vector2> getter, Action<Vector2> setter, Vector2 endValue, float duration);
public static TweenVector3 To(Func<Vector3> getter, Action<Vector3> setter, Vector3 endValue, float duration);
public static TweenVector4 To(Func<Vector4> getter, Action<Vector4> setter, Vector4 endValue, float duration);
public static TweenColor To(Func<Color> getter, Action<Color> setter, Color endValue, float duration);
public static TweenQuaternion To(Func<Quaternion> getter, Action<Quaternion> setter, Quaternion endValue, float duration);
public static TweenFloat From(Func<float> getter, Action<float> setter, float fromValue, float duration);
public static TweenVector3 From(Func<Vector3> getter, Action<Vector3> setter, Vector3 fromValue, float duration);
public static TweenColor From(Func<Color> getter, Action<Color> setter, Color fromValue, float duration);
public static TweenFloat Value(float from, float to, float duration, Action<float> onUpdate);
public static TweenVector3 Value(Vector3 from, Vector3 to, float duration, Action<Vector3> onUpdate);
public static TweenColor Value(Color from, Color to, float duration, Action<Color> onUpdate);
public static TweenSequence Sequence();
/* Bulk control. */
public static int ActiveTweenCount { get; }
public static int KillAll (bool complete = false);
public static int KillTweensOf (object target, bool complete = false);
public static int PauseAll ();
public static int ResumeAll ();
public static int CompleteAll ();
public static void Clear ();
/* Queries. */
public static ITween GetTween (TweenID id);
public static bool IsTweening (object target);
/* Global settings. */
public static void SetGlobalTimeScale(float timeScale);
public static float GlobalTimeScale { get; }
public static void SetDefaultEase (EaseType easeType);
public static void SetDefaultDuration(float duration);
public static void ResetSettings();
}
/* Interface and base. */
public interface ITween
{
TweenID ID { get; }
TweenState State { get; }
float Duration { get; }
float ElapsedTime { get; }
float Delay { get; }
float Progress { get; }
EaseType EaseType { get; }
LoopType LoopType { get; }
int Loops { get; }
int CompletedLoops { get; }
float TimeScale { get; }
bool IsPlaying { get; }
bool IsComplete { get; }
bool IsPaused { get; }
bool IsKilled { get; }
bool IsManaged { get; }
bool AutoKill { get; }
object Target { get; }
ITween Play(); ITween Pause(); ITween Kill(bool complete = false);
ITween Restart(); ITween Complete(); ITween Rewind();
void Update(float deltaTime);
ITween SetEase (EaseType easeType);
ITween SetEase (Func<float, float> easeFunction);
ITween SetDelay (float delay);
ITween SetTimeScale(float timeScale);
ITween SetDuration (float duration);
ITween SetLoops (int loops, LoopType loopType = LoopType.Restart);
ITween SetManaged (bool managed);
ITween SetAutoKill (bool autoKill);
ITween SetTarget (object target);
ITween OnStart (Action callback);
ITween OnUpdate (Action callback);
ITween OnComplete (Action callback);
ITween OnKill (Action callback);
ITween OnLoopComplete (Action callback);
ITween OnPause (Action callback);
ITween OnResume (Action callback);
}
public abstract class TweenBase : ITween { /* implements ITween + Reset() */ }
public class Tween<T> : TweenBase
{
public T StartValue { get; }
public T EndValue { get; }
public Tween();
public Tween(Func<T> getter, Action<T> setter, T endValue, float duration, Func<T, T, float, T> lerpFunction);
public Tween<T> Initialize (Func<T> getter, Action<T> setter, T endValue, float duration, Func<T, T, float, T> lerpFunction);
public Tween<T> SetFrom (T fromValue);
public Tween<T> SetChangeValue(T changeValue);
}
public sealed class TweenFloat : TweenBase { /* float interpolation */ }
public sealed class TweenVector2 : TweenBase { /* Vector2 interpolation */ }
public sealed class TweenVector3 : TweenBase { /* Vector3 interpolation */ }
public sealed class TweenVector4 : TweenBase { /* Vector4 interpolation */ }
public sealed class TweenColor : TweenBase { /* Color RGBA interpolation */ }
public sealed class TweenQuaternion : TweenBase { /* Quaternion slerp */ }
/* Sequence. */
public sealed class TweenSequence : ITween
{
public int ItemCount { get; }
public TweenSequence Append (ITween tween);
public TweenSequence Join (ITween tween);
public TweenSequence Insert (float atPosition, ITween tween);
public TweenSequence Prepend (ITween tween);
public TweenSequence AppendInterval (float interval);
public TweenSequence PrependInterval(float interval);
public TweenSequence AppendCallback (Action callback);
public TweenSequence InsertCallback (float atPosition, Action callback);
/* + every ITween method */
}
/* Pool and manager. */
public static class TweenPool
{
public static bool IsInitialized { get; }
public static int FloatPoolCount { get; }
public static int Vector3PoolCount{ get; }
/* + per-type pool counts */
public static void Initialize();
public static void Initialize(int initialCapacity, int maxSize);
public static void Prewarm (int count);
public static void Clear ();
public static TweenFloat GetFloat();
public static TweenVector2 GetVector2();
public static TweenVector3 GetVector3();
public static TweenVector4 GetVector4();
public static TweenColor GetColor();
public static TweenQuaternion GetQuaternion();
public static TweenSequence GetSequence();
public static void Release(TweenFloat tween);
/* + Release for every type */
}
public static class TweenManager
{
public static int ActiveTweenCount { get; }
public static bool IsUpdating { get; }
public static void Update(float deltaTime);
public static void Register (ITween tween);
public static void Unregister (ITween tween);
public static ITween GetTween (TweenID id);
public static IReadOnlyList<ITween> GetTweensByTarget(object target);
public static bool HasTweens (object target);
public static int KillTweensByTarget (object target, bool complete = false);
public static int PauseTweensByTarget(object target);
public static int ResumeTweensByTarget(object target);
public static int KillAll(bool complete = false);
public static int PauseAll();
public static int ResumeAll();
public static int CompleteAll();
public static void Clear();
}
/* Ease evaluator. */
public static class Ease
{
public static float Evaluate (EaseType easeType, float t);
public static Func<float, float> GetFunction(EaseType easeType);
/* 33 named curves: Linear, In/Out/InOut for Sine, Quad, Cubic, Quart,
* Quint, Expo, Circ, Elastic, Back, Bounce, plus Flash. */
public static float Linear (float t);
public static float InQuad (float t); public static float OutQuad (float t); public static float InOutQuad (float t);
public static float InCubic (float t); public static float OutCubic (float t); public static float InOutCubic (float t);
/* ... and so on for Sine / Quart / Quint / Expo / Circ / Elastic / Back / Bounce */
}
/* Settings, exception, identifier. */
public static class TweenSettings
{
public static float GlobalTimeScale { get; set; } /* default 1.0 */
public static EaseType DefaultEaseType { get; set; } /* default Linear */
public static float DefaultDuration { get; set; } /* default 1.0s */
public static bool DefaultAutoKill { get; set; } /* default true */
public static int DefaultPoolCapacity { get; set; } /* default 64 */
public static int DefaultPoolMaxSize { get; set; } /* default 500 */
public static void ResetToDefaults();
}
public class TweenException : Exception
{
public TweenID TweenID { get; }
public TweenErrorCode ErrorCode { get; }
/* Constructors with combinations of message, ErrorCode, TweenID, inner. */
}
public enum TweenErrorCode { Unknown, /* ... per-failure codes */ }
public struct TweenID { /* opaque stable handle */ }
/* Enums. */
public enum TweenState { Created, Delayed, Playing, Paused, Complete, Killed }
public enum LoopType { Restart, Yoyo, Incremental }
public enum EaseType { Linear, InSine, OutSine, InOutSine, InQuad, OutQuad, InOutQuad,
InCubic, OutCubic, InOutCubic, InQuart, OutQuart, InOutQuart,
InQuint, OutQuint, InOutQuint, InExpo, OutExpo, InOutExpo,
InCirc, OutCirc, InOutCirc, InElastic, OutElastic, InOutElastic,
InBack, OutBack, InOutBack, InBounce, OutBounce, InOutBounce,
Flash, Custom }
/* Sequence items. */
public struct SequenceItem { /* tween, callback, or interval entry */ }
public enum SequenceItemType { Tween, Callback, Interval }
/* ITween extension methods (chainable). */
public static class TweenExtensions
{
public static ITween PlayManaged (this ITween tween);
public static ITween PlayWithEase (this ITween tween, EaseType easeType);
public static ITween PlayDelayed (this ITween tween, float delay);
public static ITween OnProgress (this ITween tween, Action<float> callback);
public static ITween OnCompleteKill (this ITween tween, Action callback);
public static ITween SetLoopInfinite(this ITween tween, LoopType loopType = LoopType.Restart);
public static ITween SetPingPong (this ITween tween, int loops = -1);
public static TweenFloat AsFloat (this ITween tween);
public static TweenVector3 AsVector3 (this ITween tween);
public static TweenColor AsColor (this ITween tween);
public static TweenSequence AsSequence(this ITween tween);
public static ITween WaitForCompletion(this ITween tween, Action onComplete);
public static float GetRemainingTime (this ITween tween);
public static float GetTotalDuration (this ITween tween);
public static bool IsActive (this ITween tween);
public static ITween TogglePause (this ITween tween);
}
/* Six Unity-type extension classes (signatures abbreviated). */
public static class TweenTransformExtensions
{
public static TweenVector3 TweenPosition (this Transform t, Vector3 end, float duration);
public static TweenVector3 TweenLocalPosition (this Transform t, Vector3 end, float duration);
public static TweenFloat TweenPositionX/Y/Z (this Transform t, float end, float duration);
public static TweenQuaternion TweenRotation (this Transform t, Quaternion end, float duration);
public static TweenQuaternion TweenRotation (this Transform t, Vector3 endEuler, float duration);
public static TweenQuaternion TweenLocalRotation (this Transform t, Quaternion end, float duration);
public static TweenQuaternion TweenLocalRotation (this Transform t, Vector3 endEuler, float duration);
public static TweenVector3 TweenScale (this Transform t, Vector3 end, float duration);
public static TweenVector3 TweenScale (this Transform t, float uniform, float duration);
public static TweenFloat TweenScaleX/Y/Z (this Transform t, float end, float duration);
public static TweenVector3 TweenMoveBy (this Transform t, Vector3 offset, float duration);
public static TweenVector3 TweenPunchScale (this Transform t, Vector3 punch, float duration);
public static TweenVector3 TweenShakePosition (this Transform t, Vector3 strength, float duration, int vibrato = 10);
public static TweenQuaternion TweenLookAt (this Transform t, Vector3 target, float duration);
public static TweenQuaternion TweenLookAt (this Transform t, Transform target, float duration);
}
public static class TweenRectTransformExtensions
{
public static TweenVector2 TweenAnchoredPosition (this RectTransform r, Vector2 end, float duration);
public static TweenFloat TweenAnchoredPositionX/Y (this RectTransform r, float end, float duration);
public static TweenVector3 TweenAnchoredPosition3D (this RectTransform r, Vector3 end, float duration);
public static TweenVector2 TweenSizeDelta (this RectTransform r, Vector2 end, float duration);
public static TweenFloat TweenWidth/TweenHeight (this RectTransform r, float end, float duration);
public static TweenVector2 TweenPivot (this RectTransform r, Vector2 end, float duration);
public static TweenVector2 TweenAnchorMin/Max (this RectTransform r, Vector2 end, float duration);
}
public static class TweenCanvasGroupExtensions
{
public static TweenFloat TweenAlpha (this CanvasGroup g, float end, float duration);
public static TweenFloat TweenFadeIn (this CanvasGroup g, float duration);
public static TweenFloat TweenFadeOut (this CanvasGroup g, float duration);
public static TweenFloat TweenFade (this CanvasGroup g, float end, float duration, bool setInteractable = true);
}
public static class TweenSpriteRendererExtensions
{
public static TweenColor TweenColor (this SpriteRenderer sr, Color end, float duration);
public static TweenColor TweenAlpha (this SpriteRenderer sr, float end, float duration);
public static TweenColor TweenFadeIn (this SpriteRenderer sr, float duration);
public static TweenColor TweenFadeOut (this SpriteRenderer sr, float duration);
}
public static class TweenMaterialExtensions
{
public static TweenColor TweenColor (this Material m, Color end, float duration);
public static TweenColor TweenColor (this Material m, string propertyName, Color end, float duration);
public static TweenColor TweenColor (this Material m, int propertyID, Color end, float duration);
public static TweenColor TweenAlpha (this Material m, float end, float duration);
public static TweenFloat TweenFloat (this Material m, string propertyName, float end, float duration);
public static TweenFloat TweenFloat (this Material m, int propertyID, float end, float duration);
public static TweenVector4 TweenVector (this Material m, string propertyName, Vector4 end, float duration);
public static TweenVector4 TweenVector (this Material m, int propertyID, Vector4 end, float duration);
public static TweenVector2 TweenTextureOffset (this Material m, Vector2 end, float duration);
public static TweenVector2 TweenTextureScale (this Material m, Vector2 end, float duration);
}
public static class TweenAudioSourceExtensions
{
public static TweenFloat TweenVolume (this AudioSource s, float end, float duration);
public static TweenFloat TweenFadeIn (this AudioSource s, float duration);
public static TweenFloat TweenFadeOut (this AudioSource s, float duration);
public static TweenFloat TweenFadeOutAndStop(this AudioSource s, float duration);
public static TweenFloat TweenPitch (this AudioSource s, float end, float duration);
public static TweenFloat TweenSpatialBlend (this AudioSource s, float end, float duration);
public static TweenFloat TweenPanStereo (this AudioSource s, float end, float duration);
}
}
See the API reference for full signatures, remarks, and exception contracts on every member.
Easing reference
The EaseType enum lists 33 named curves plus Custom. Every curve takes t in [0, 1] as its input; the table below summarises the visual effect and a typical use case for each family. Pick the family by intent, then pick In / Out / InOut by where you want the motion to accelerate.
| Family | Variants | Curve shape (start to finish) | Typical use case |
|---|---|---|---|
Linear | Linear | Constant rate | No easing applied. Generally avoid for visual animation; use for value-tweens (counters, progress bars). |
Sine | InSine, OutSine, InOutSine | Gentle sinusoidal curve | Soft motion. Lighter than Quad; useful when the easing should feel subtle. |
Quad | InQuad, OutQuad, InOutQuad | Quadratic acceleration / deceleration | Standard motion. OutQuad is the safe default for “ease to a halt”. |
Cubic | InCubic, OutCubic, InOutCubic | Stronger than Quad, weaker than Quart | More pronounced easing. OutCubic reads as a confident stop. |
Quart | InQuart, OutQuart, InOutQuart | Stronger acceleration / deceleration | Sharp settle; OutQuart works for camera transitions that should feel decisive. |
Quint | InQuint, OutQuint, InOutQuint | Strongest non-exotic curve | Heavy easing; OutQuint is a hard ease-to-rest. |
Expo | InExpo, OutExpo, InOutExpo | Exponential | Snap-style start or stop. Visually similar to Quint but with more bias at the extremes. |
Circ | InCirc, OutCirc, InOutCirc | Circular arc | Smooth-to-the-end curve; pairs well with arcs in motion (e.g. arc-trajectory projectiles). |
Elastic | InElastic, OutElastic, InOutElastic | Overshoot then oscillate | Springy reveal; useful for popping UI elements into view. |
Back | InBack, OutBack, InOutBack | Slight pull-back before or after | Charge-up motion; OutBack is a small overshoot that reads as a snap. |
Bounce | InBounce, OutBounce, InOutBounce | Decaying bounces | Drop-in feel; OutBounce for “land and bounce” character feedback. |
Flash | Flash | Discrete on/off | Simple flash effect; pairs with damage feedback and warnings. |
Custom | Custom | Indicates a custom Func<float, float> is in use | Set via SetEase(Func<float, float>). The enum value itself is informational. |
TweenSettings reference
TweenSettings is the static carrier for the global defaults. You can adjust them via the corresponding ScyllaTween.Set* methods or directly on the properties. ResetToDefaults() reverts every value to its factory default.
| Property | Type | Default | Effect |
|---|---|---|---|
GlobalTimeScale | float | 1.0 | Multiplier applied to every tween’s elapsed time. Use for slow-motion or fast-forward across the entire tween subsystem. |
DefaultEaseType | EaseType | Linear | Ease used when you construct a tween without an explicit SetEase. Setting to OutCubic project-wide is a sensible upgrade. |
DefaultDuration | float | 1.0s | Duration used when no explicit duration is provided. Currently affects only specific tween paths; most factories require an explicit duration. |
DefaultAutoKill | bool | true | Whether tweens auto-release to the pool on completion. Set to false only when you need manual control over re-runs. |
DefaultPoolCapacity | int | 64 | Initial pool capacity per type. Increase for projects with many simultaneous tweens. |
DefaultPoolMaxSize | int | 500 | Maximum pool size per type before excess instances are released to the GC instead of returned. This caps unbounded growth. |
Best Practices
- Always set an ease. The default
Linearcurve almost always looks worse thanOutQuadfor fade-ins,OutCubicfor ease-to-rest,InOutCubicfor general transitions, orOutBackfor a small overshoot. Set the project default viaScyllaTween.SetDefaultEase(EaseType.OutCubic)and only override per-tween when a different curve is needed. - Prefer
PlayManaged()overPlay()for almost every use case. The framework’s per-frame runner handles the tick, the destroyed-target detection, and the auto-release. Manual play is for tests, paused-game logic, and custom run loops. - Use
TweenSequencefor any multi-stage animation. ChainedOnCompletecallbacks work but produce a tangled call graph that is hard to interrupt mid-sequence. A sequence is one declarative block, can be paused or killed as a unit, and supports parallelism viaJoin. - Pool first, allocate never. Call
ScyllaTween.Prewarm(128)at startup to pre-allocate the instances every subsequent tween needs. Without prewarm the first batch produces one allocation per tween; with prewarm, the first thousand-plus tweens come from the pool with no GC. - Wire
PauseAll/ResumeAllto your game’s pause events. Tweens continue running while the rest of the simulation is paused unless their tick is suspended explicitly. Combining withSetGlobalTimeScale(0f)is the alternative when you want to freeze without pausing the manager. - Use
KillTweensOf(target)in entity teardown. When an entity is destroyed mid-animation, any tween still operating on it will throw when the setter dereferences the destroyed object. The framework auto-detects destroyed Unity objects in the manager loop, but explicit cleanup inOnDestroyis faster and more predictable. - Use
SetTarget(target)on tweens for which target-based queries matter. The manager indexes tweens by target only whenSetTarget(or the convenience extensions that call it internally) was used. Pure value tweens (Value) typically don’t need a target. - Pre-resolve material property IDs.
Shader.PropertyToID("_BaseColor")runs a string hash on every call; resolving once at startup and passing the integer tomaterial.TweenColor(id, ...)avoids the per-call lookup. Useful when many material tweens fire per frame. - Reach for
TweenShakePositionover a manual shake loop. The extension handles the trauma decay, the random vibrato, and the auto-return to the original position. Hand-written shakes tend to forget the return-to-rest step and leave the transform offset after the effect. - Use
SetLoopInfiniteand a target-based kill for ambient effects. A breathing idle, a wobble, a glow: infinite tweens that should run until the owner is destroyed. Pair withOnDestroycleanup viaScyllaTween.KillTweensOf(this)so the manager doesn’t accumulate stale instances. - Pre-build sequences for reused choreography. A sequence built once and stored on a controller can be
Restart-ed instead of rebuilt per trigger, saving the per-launch allocation cost and the construction time. - Match the tween type to the value type. Use
TweenFloatfor single-axis values (X position, alpha, volume); useTweenVector3for combined-axis values. Animating a 3D position via three separateTweenFloatinstances produces three times the bookkeeping and three call sites for the setters. - Use
Ease.Evaluatedirectly when the tween manager is overkill. A one-frame interpolation inside an existingUpdatedoesn’t need a tween; callEase.Evaluate(EaseType.OutCubic, t)and apply the result. Reserve tweens for time-bounded animations.
Pitfalls
Related
- Math Utils
- UI Layout Utils
- Object Pools
- Scene Manager
- API reference:
Scylla.Core.Util.Tween.ScyllaTween - API reference:
Scylla.Core.Util.Tween.ITween - API reference:
Scylla.Core.Util.Tween.TweenBase - API reference:
Scylla.Core.Util.Tween.Tween`1 - API reference:
Scylla.Core.Util.Tween.TweenFloat - API reference:
Scylla.Core.Util.Tween.TweenVector2 - API reference:
Scylla.Core.Util.Tween.TweenVector3 - API reference:
Scylla.Core.Util.Tween.TweenVector4 - API reference:
Scylla.Core.Util.Tween.TweenColor - API reference:
Scylla.Core.Util.Tween.TweenQuaternion - API reference:
Scylla.Core.Util.Tween.TweenSequence - API reference:
Scylla.Core.Util.Tween.TweenManager - API reference:
Scylla.Core.Util.Tween.TweenPool - API reference:
Scylla.Core.Util.Tween.TweenSettings - API reference:
Scylla.Core.Util.Tween.TweenExtensions - API reference:
Scylla.Core.Util.Tween.TweenException - API reference:
Scylla.Core.Util.Tween.TweenErrorCode - API reference:
Scylla.Core.Util.Tween.TweenID - API reference:
Scylla.Core.Util.Tween.TweenState - API reference:
Scylla.Core.Util.Tween.Ease - API reference:
Scylla.Core.Util.Tween.EaseType - API reference:
Scylla.Core.Util.Tween.LoopType - API reference:
Scylla.Core.Util.Tween.SequenceItem - API reference:
Scylla.Core.Util.Tween.SequenceItemType - API reference:
Scylla.Core.Util.Tween.TweenTransformExtensions - API reference:
Scylla.Core.Util.Tween.TweenRectTransformExtensions - API reference:
Scylla.Core.Util.Tween.TweenCanvasGroupExtensions - API reference:
Scylla.Core.Util.Tween.TweenSpriteRendererExtensions - API reference:
Scylla.Core.Util.Tween.TweenMaterialExtensions - API reference:
Scylla.Core.Util.Tween.TweenAudioSourceExtensions