VRCTween
VRCTween allows you to create smooth animations in your VRChat worlds using the powerful DOTween library. You can animate positions, rotations, scales, and more with a few lines of code.
Overview
VRCTween is a built-in tweening system that smoothly interpolates (or "tweens") values over time. Instead of manually updating positions or rotations frame-by-frame, VRCTween handles the math and timing for you.
Common use cases:
- Animate UI elements such as buttons, panels, and menus.
- Create smooth object movements.
- Add polish to your world.
VRCTween uses DOTween, a popular Unity tweening library, and works with both UdonSharp and Udon Graph.
Basic usage
Create a tween
Create tweens using extension methods on the target type, or static methods on VRCTween. Each method returns a VRCTweenHandle that you can use to control and configure the tween:
using VRC.SDK3.Components;
public class MyScript : UdonSharpBehaviour
{
public GameObject cube;
void Start()
{
// Move the cube up over 2 seconds.
VRCTweenHandle tweenHandle = cube.TweenPosition(new Vector3(0, 5, 0), 2f, VRCTweenEase.OutQuad);
}
}
Receive callbacks
To receive a notification when a tween completes, chain .OnComplete() on the handle:
public class MyScript : UdonSharpBehaviour
{
void Start()
{
gameObject.TweenScale(Vector3.one * 2f, 1f, VRCTweenEase.OutBounce)
.OnComplete(this, nameof(OnScaleComplete));
}
public void OnScaleComplete()
{
Debug.Log("Scale animation complete!");
}
}
Tween types
Tween creation methods are available as extension methods on the target type (e.g., gameObject.TweenPosition(...)) or as static methods on VRCTween. All return a VRCTweenHandle.
- Transform: TweenPosition, TweenLocalPosition, TweenRotation, TweenLocalRotation, TweenScale
- Path: TweenPath, TweenLocalPath
- UI: TweenColor, TweenFade (Graphic), TweenFade (CanvasGroup), TweenValue (Slider), TweenAnchorPos, TweenSizeDelta
- Sprite: TweenColor, TweenFade (SpriteRenderer)
- Renderer: TweenColor, TweenFloat (Renderer)
- Light: TweenIntensity, TweenColor (Light)
- Audio: TweenVolume (AudioSource)
For detailed code examples, see Built-in Tween Types.
Virtual Tweens
Virtual tweens animate arbitrary values (float, int, Color, Vector3) by writing into a variable on your UdonBehaviour each frame. Use them when none of the built-in tween types cover what you need. See Virtual Tweens for details and examples.
Controlling and configuring tweens
Control and configure tweens using instance methods on VRCTweenHandle. Config methods return the handle for chaining:
cube.TweenPosition(new Vector3(0, 5, 0), 2f, VRCTweenEase.OutQuad)
.From()
.SetDelay(0.5f)
.SetLoops(2, VRCTweenLoopType.Yoyo)
.OnComplete(this, nameof(OnDone));
See Settings and Control for the full API reference and ease type table.
Example
This example demonstrates handle storage, callbacks, and cleanup:
using UdonSharp;
using UnityEngine;
using VRC.SDK3.Components;
public class TweenExample : UdonSharpBehaviour
{
public GameObject button;
private VRCTweenHandle scaleTween;
public override void Interact()
{
// Scale up and down when clicked.
scaleTween = button.TweenScale(Vector3.one * 1.2f, 0.15f, VRCTweenEase.OutQuad)
.OnComplete(this, nameof(OnTweenComplete));
}
public void OnTweenComplete()
{
// Scale back down.
button.TweenScale(Vector3.one, 0.15f, VRCTweenEase.OutQuad);
}
void OnDestroy()
{
// Clean up tweens when object is destroyed.
button.KillAllTweens();
}
}
Best practices
Store tween handles
Save tween handles if you need to control them later:
private VRCTweenHandle myTween;
void Start()
{
myTween = gameObject.TweenPosition(Vector3.up, 2f, VRCTweenEase.OutQuad);
}
public void StopTween()
{
myTween.Kill();
}
Clean up tweens
Tweens are automatically cleaned up when they complete. However, tweens that are still running (e.g., infinite loops or long-duration tweens) should be killed when their object is destroyed:
void OnDestroy()
{
gameObject.KillAllTweens();
}
Chain tweens with callbacks
Create sequences by using callbacks and custom event names:
void Start()
{
cube.TweenPosition(Vector3.up * 5, 1f, VRCTweenEase.OutQuad)
.OnComplete(this, nameof(OnFirstTweenComplete));
}
public void OnFirstTweenComplete()
{
cube.TweenRotation(new Vector3(0, 180, 0), 1f, VRCTweenEase.InOutQuad)
.OnComplete(this, nameof(OnSecondTweenComplete));
}
public void OnSecondTweenComplete()
{
Debug.Log("Sequence complete!");
}
Use DelayedCall for cancelable timers
VRCTween.DelayedCall is a cancelable alternative to SendCustomEventDelayedSeconds:
private VRCTweenHandle timerHandle;
void Start()
{
// Schedule a delayed callback.
timerHandle = VRCTween.DelayedCall(this, nameof(OnTimerFinished), 3.0f);
}
public void CancelTimer()
{
// Cancel the timer at any time.
timerHandle.Kill();
}
public void OnTimerFinished()
{
Debug.Log("3 seconds have passed!");
}
Udon Graph
VRCTween works in Udon Graph. Look for the VRCTween and VRCTweenHandle nodes in the node search:
- Search for "VRCTween TweenPosition" (or any creation method) to create a tween.
- Connect your GameObject and parameters.
- The node outputs a
VRCTweenHandle. - Use
VRCTweenHandlenodes (Kill, Pause, SetDelay, OnComplete, etc.) to control and configure it.
For callbacks, use the VRCTweenHandle OnComplete node:
- Connect the tween handle and your UdonBehaviour (usually "this").
- Provide a custom event name string.
- Implement the corresponding custom event in your graph.
Limitations
- Tweens are local to each player and don't sync across the network automatically.
- For networked animations, consider using Udon's networking features alongside tweens.
- Very short tween durations (less than 0.01 seconds) may not animate smoothly.
- Tween handles are unique per scene instance.
Performance tips
Reuse tweens instead of killing and recreating them
Killing a tween and creating a new one allocates memory every time. Reusing an existing handle with ChangeEndValue, SetDuration, and SetEase avoids those allocations entirely. In internal benchmarks with 500 tweens running over 300 frames, the reuse pattern allocated 46× less memory and ran 10× faster than kill-and-recreate.
Even at typical world scales (5–50 tweens), reuse cuts allocations by roughly 3× compared to recreating tweens. The difference matters most when tweens change frequently, such as UI elements that follow a moving target or objects responding to player input each frame.
VRCTweenHandle _moveHandle;
void Start()
{
// Create once with infinite loops so it stays alive after completing.
_moveHandle = gameObject.TweenPosition(Vector3.zero, 1f, VRCTweenEase.OutQuad)
.SetLoops(-1, VRCTweenLoopType.Restart)
.Pause();
}
public void MoveTo(Vector3 target, float duration)
{
// Reconfigure and restart — no allocation.
_moveHandle.ChangeEndValue(target, true)
.SetDuration(duration)
.SetEase(VRCTweenEase.OutCubic);
_moveHandle.Restart();
}
See Tween reuse in Settings and Control for more details.
General tips
- Use
KillAllTweens()to clean up all tweens on an object at once. - Avoid creating hundreds of simultaneous tweens. Stagger them if needed.
Resources
- DOTween Documentation - Learn about the underlying library.
- Ease Visualizer - See how different ease types look.