Tween - VirtueSky/sunflower GitHub Wiki
Tween
Simple custom tween module for Unity.
Namespace: VirtueSky.Tweening
Goal
This module provides a small tween API with a LitMotion-like flow:
Tween.Create(...).WithEase(...).BindTo...
Designed to keep the tween core low-allocation / zero-GC on runtime when using the built-in bind helpers.
Main API
Entry points
Tween.Create(from, to, duration) // returns a typed builder
Tween.Delay(duration, onComplete) // fire-and-forget timer
Supported value types: float, Vector2, Vector3, Vector4, Color, Quaternion
Builder chain methods (all types)
| Method | Description |
|---|---|
WithEase(Ease) |
Set easing function |
WithDelay(float) |
Delay before starting |
WithUnscaledTime(bool) |
Use Time.unscaledDeltaTime |
WithCurve(AnimationCurve) |
Custom animation curve |
WithOnStart(Action) |
Callback fired once when tween starts (after delay) |
WithOnComplete(Action) |
Callback fired when tween finishes |
WithLoops(int) |
Number of loops: -1 = infinite, 1 = once (default), N = N times |
WithLoopType(LoopType) |
LoopType.Restart (default) or LoopType.PingPong |
OnValueChanged(Action<T>) |
Callback fired every frame with current value (same as DOTween's OnUpdate) |
Bind(Action<T>) |
OnValueChanged + Play() combined — terminates the builder |
Play() |
Start the tween, returns a TweenHandle |
TweenHandle
handle.IsActive // true if still running
handle.IsPaused // true if paused
handle.Cancel() // stop immediately, no OnComplete
handle.Complete() // jump to end value, fires OnComplete
handle.Pause() // freeze in place
handle.Resume() // continue from where it paused
Quick Start
using VirtueSky.Tweening;
// Scale popup
TweenHandle handle = Tween.Create(Vector3.zero, Vector3.one, 0.25f)
.WithEase(Ease.OutBack)
.BindToLocalScale(transform);
// Cancel on destroy
void OnDisable() => handle.Cancel();
Tween.Delay
// Fire a callback after 1.5 seconds
Tween.Delay(1.5f, () => ShowNextPanel());
// With unscaled time (works when Time.timeScale == 0)
Tween.Delay(0.3f, () => HidePauseMenu(), unscaledTime: true);
// Cancellable
TweenHandle timer = Tween.Delay(5f, OnCountdownEnd);
timer.Cancel(); // cancel before it fires
Loop
// Infinite loop — bounce scale
Tween.Create(Vector3.one, Vector3.one * 1.1f, 0.5f)
.WithLoops(-1)
.WithLoopType(LoopType.PingPong)
.WithEase(Ease.InOutSine)
.BindToLocalScale(transform);
// Play exactly 3 times then stop
Tween.Create(0f, 1f, 0.4f)
.WithLoops(3)
.BindToFillAmount(image);
OnStart / OnComplete
Tween.Create(0f, 1f, 0.5f)
.WithDelay(1f)
.WithOnStart(() => Debug.Log("started after 1s delay"))
.WithOnComplete(() => Debug.Log("done"))
.BindToAlpha(canvasGroup);
Pause / Resume
TweenHandle handle = Tween.Create(startPos, endPos, 2f)
.BindToLocalPosition(transform);
// On game pause
handle.Pause();
// On game resume
handle.Resume();
if (handle.IsPaused) { ... }
Available Bind Helpers
Vector3TweenBuilder
| Method | Target |
|---|---|
BindToPosition(Transform) |
transform.position |
BindToLocalPosition(Transform) |
transform.localPosition |
BindToLocalScale(Transform) |
transform.localScale |
BindToEulerAngles(Transform) |
transform.eulerAngles |
BindToLocalEulerAngles(Transform) |
transform.localEulerAngles |
QuaternionTweenBuilder
| Method | Target |
|---|---|
BindToRotation(Transform) |
transform.rotation |
BindToLocalRotation(Transform) |
transform.localRotation |
ColorTweenBuilder
| Method | Target |
|---|---|
BindToColor(SpriteRenderer) |
spriteRenderer.color |
BindToColor(Graphic) |
graphic.color |
FloatTweenBuilder
| Method | Target |
|---|---|
BindToAlpha(CanvasGroup) |
canvasGroup.alpha |
BindToFillAmount(Image) |
image.fillAmount |
BindToLocalPositionX(Transform) |
localPosition.x |
BindToLocalPositionY(Transform) |
localPosition.y |
BindToLocalPositionZ(Transform) |
localPosition.z |
BindToAnchoredPositionX(RectTransform) |
anchoredPosition.x |
BindToAnchoredPositionY(RectTransform) |
anchoredPosition.y |
Vector2TweenBuilder
| Method | Target |
|---|---|
BindToAnchoredPosition(RectTransform) |
anchoredPosition |
BindToSizeDelta(RectTransform) |
sizeDelta |
Examples
Move (world space)
Tween.Create(transform.position, new Vector3(0f, 3f, 0f), 0.5f)
.WithEase(Ease.OutCubic)
.BindToPosition(transform);
Scale
Tween.Create(Vector3.one, Vector3.one * 1.1f, 0.2f)
.WithEase(Ease.OutBack)
.BindToLocalScale(transform);
Rotate
Tween.Create(transform.localRotation, Quaternion.Euler(0f, 180f, 0f), 0.4f)
.WithEase(Ease.InOutSine)
.BindToLocalRotation(transform);
Fade CanvasGroup
Tween.Create(0f, 1f, 0.25f)
.BindToAlpha(canvasGroup);
UI slide in
Tween.Create(new Vector2(0f, -200f), Vector2.zero, 0.35f)
.WithEase(Ease.OutQuart)
.BindToAnchoredPosition(rectTransform);
Resize panel
Tween.Create(new Vector2(100f, 100f), new Vector2(400f, 300f), 0.3f)
.WithEase(Ease.OutCubic)
.BindToSizeDelta(rectTransform);
Heartbeat loop
Tween.Create(Vector3.one, Vector3.one * 1.15f, 0.3f)
.WithLoops(-1)
.WithLoopType(LoopType.PingPong)
.WithEase(Ease.InOutSine)
.BindToLocalScale(transform);
Delayed chain (manual)
Tween.Create(0f, 1f, 0.3f)
.WithOnComplete(() =>
Tween.Delay(0.5f, () =>
Tween.Create(1f, 0f, 0.3f).BindToAlpha(canvasGroup)))
.BindToAlpha(canvasGroup);
Zero-GC Usage
Prefer built-in BindTo... helpers. They route through the internal binding path and avoid delegate allocation at call site.
// Recommended (zero-GC at call site)
Tween.Create(transform.position, target, 0.3f)
.BindToPosition(transform);
// Allocates a delegate/closure
Tween.Create(transform.position, target, 0.3f)
.Bind(v => transform.position = v);
WithOnComplete and WithOnStart can also allocate if the lambda captures outer variables.
Ease
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 · CustomAnimationCurve
Notes
- Storage is fixed-size: 256 tweens per value type. Full storage logs an error instead of resizing.
- A hidden
[VirtueSky.TweenRunner]GameObject is created automatically on first use (DontDestroyOnLoad). - Auto-cancel: if a bound target (Transform, RectTransform, etc.) is destroyed mid-tween, the entry deactivates automatically on the next frame.
WithLoops(-1)withLoopType.PingPongswapsFrom/Toeach cycle in-place on the entry struct.
Files
| File | Role |
|---|---|
Tween.cs |
Entry API (Tween.Create, Tween.Delay) |
TweenBuilder.cs |
Builder structs, LoopType enum, bind extensions |
TweenHandle.cs |
Handle struct (cancel / complete / pause / resume) |
TweenRuntime.cs |
Internal runtime and per-type storage |
TweenRunner.cs |
MonoBehaviour driver |
Ease.cs |
Ease enum |
EaseUtility.cs |
Ease evaluation |