Luna provides a powerful Transition Animation system for creating smooth, reusable UI animations using UI Toolkit's CSS transitions. Build complex animation sequences declaratively via ScriptableObjects or programmatically with a fluent API.

.Bounce(), .FadeIn(), .FadeOut(), .SlideIn(), .SlideOut(), .Pulse() methods on the builderStyleProperty enumPlayOverlay / PlayOverlayInstance nodes, with automatic handle cleanupThe simplest way to add animations is through the TransitionAnimator component:
TransitionAnimator to a GameObjectUIDocument or UIViewComponent// Play animation manually
transitionAnimator.Play();
// Or enable "Play On Enable" in the InspectorLuna includes 52 preset animation assets. Simply reference them in the TransitionAnimator:
// Load and play a preset directly
TransitionSequenceAsset fadeIn = Resources.Load<TransitionSequenceAsset>("TransitionPresets/Base/FadeIn");
var player = fadeIn.CreatePlayer();
player.Play(myElement);Build animations programmatically with the TransitionSequence builder:
var sequence = new TransitionSequence()
.Opacity(0f, 0.3f, EasingMode.EaseOut) // Fade out
.Scale(0.8f, 0.3f, EasingMode.EaseOut) // Scale down
.Build();
var player = new TransitionSequencePlayer(sequence);
player.OnComplete += () => Debug.Log("Animation complete!");
player.Play(myElement);MonoBehaviour that plays transition animations on VisualElements.
| Property | Description |
|---|---|
| Nodes | Ordered list of animation nodes (inline step groups or sub-sequence asset references) |
| Play Mode | Once, Loop, PingPong, or LoopCount |
| Loop Count | Number of loops when Play Mode is LoopCount |
| UI View Component | Optional UIViewComponent reference for target resolution |
| UI Document | UIDocument reference (used when no UIViewComponent is set) |
| Element Name | Name of the target VisualElement (leave empty for root) |
| Fade Trigger | Which UIView fade event triggers this animation |
| Play On Enable | Automatically play when the component is enabled |
// Play the animation on the configured element
public void Play()
// Play on a specific element
public void Play(VisualElement target)
// Stop playback
public void Stop()
// Pause/Resume
public void Pause()
public void Resume()
// Create a sequence or player from this animator's nodes
public TransitionSequence CreateSequence()
public TransitionSequencePlayer CreatePlayer()UnityEvent OnComplete; // Fired when animation completes
UnityEvent OnStopped; // Fired when animation is stoppedScriptableObject for defining reusable animation sequences. Create via: Create > CupkekGames > Luna > Transition Sequence
Supports:
Runtime player for executing transition sequences on a VisualElement.
// Create from a built sequence
var player = new TransitionSequencePlayer(sequence);
// Or from an asset
var player = myAsset.CreatePlayer();
// Enable debug logging
player.Debug = true;
// Play on target
player.Play(myElement);
// Check state
bool isPlaying = player.IsPlaying;
bool isPaused = player.IsPaused;
int currentNode = player.CurrentNodeIndex;
int currentIteration = player.CurrentIteration;When Play() is called on an element that already has an active TransitionSequencePlayer, the previous player is automatically stopped before the new one starts. This prevents conflicting animations from overlapping on the same element:
var player1 = new TransitionSequencePlayer(bounceSequence);
var player2 = new TransitionSequencePlayer(fadeSequence);
player1.Play(myElement); // starts playing
player2.Play(myElement); // automatically stops player1, then starts player2event Action OnComplete; // Sequence fully complete
event Action<int> OnIterationComplete; // After each loop pass
event Action OnStopped; // Playback stopped via Stop()The TransitionSequence class provides a fluent API for building animations:
var sequence = new TransitionSequence()
// Opacity
.Opacity(1f, 0.3f)
.Opacity(0f, 0.3f, EasingMode.EaseOut)
// Scale (uniform or separate x/y)
.Scale(1.2f, 0.2f)
.Scale(new Vector2(1.5f, 1f), new TransitionTimingConfig(0.3f, EasingMode.EaseInOut))
// Translate (pixels or percent)
.Translate(0f, -20f, 0.3f)
.TranslatePercent(0f, -50f, 0.3f)
// Rotate (degrees)
.Rotate(360f, 0.5f)
// Colors
.BackgroundColor(Color.red, 0.2f)
.Color(Color.blue, StyleColorProperty.BorderColor, new TransitionTimingConfig(0.2f))
// Length properties
.Width(new Length(200, LengthUnit.Pixel), new TransitionTimingConfig(0.3f))
.Height(new Length(50, LengthUnit.Percent), new TransitionTimingConfig(0.3f))
.Build();Run multiple animations simultaneously:
var sequence = new TransitionSequence()
.Together(sub => sub
.Opacity(1f, 0.3f)
.Scale(1f, 0.3f)
.Translate(0f, 0f, 0.3f)
)
.Build();var sequence = new TransitionSequence()
.Opacity(0f, 0.3f)
.Delay(0.5f) // Wait 500ms
.Callback(() => Debug.Log("Halfway done!"))
.Opacity(1f, 0.3f)
.Build();Repeat a group of steps a fixed number of times:
var sequence = new TransitionSequence()
.Repeat(3, r => r
.Scale(1.1f, 0.15f, EasingMode.EaseInOut)
.Scale(1f, 0.15f, EasingMode.EaseInOut)
)
.Build();If count is 1, the nodes are inlined directly without a repeat wrapper.
Fire a particle effect or VFX overlay on a UI element at a specific point in your animation sequence — no custom code or Callback needed. This integrates directly with the UIRender system.
Fluent API:
var sequence = new TransitionSequence()
.Scale(1.2f, 0.2f, EasingMode.EaseOut)
.PlayOverlay(sparksPrefab) // fire-and-forget
.Scale(1f, 0.2f, EasingMode.EaseIn)
.Build();With settings:
var overlaySettings = new UIOverlaySettings.Builder()
.WithAnchor(OverlayAnchor.Center)
.WithOverflowVisible(true)
.Build();
var sequence = new TransitionSequence()
.PlayOverlay(sparksPrefab, renderSettings, overlaySettings)
.Build();Blocking mode — wait for particles to finish before continuing:
var sequence = new TransitionSequence()
.PlayOverlay(sparksPrefab, waitForDrain: true)
.FadeOut() // only starts after particles fully drain
.Build();PlayOverlayInstance — borrow an existing scene GameObject instead of instantiating a copy:
var sequence = new TransitionSequence()
.PlayOverlayInstance(existingParticleSystem)
.Build();Target a child element instead of the sequence root:
var sequence = new TransitionSequence()
.PlayOverlay(sparksPrefab, targetElementName: "icon-slot")
.Build();Inspector (ScriptableObject): In a TransitionSequenceAsset, add a node and set its type to Overlay. Configure:
Handle cleanup: Overlay handles are automatically tracked by
TransitionSequencePlayerand released when the player is stopped, reset, or loops. You don't need to manage handle lifetimes manually.
Register a completion callback directly on the builder. It fires after all other nodes:
var sequence = new TransitionSequence()
.FadeIn()
.Bounce()
.OnComplete(() => Debug.Log("All done!"))
.Build();Note:
.OnComplete()on the builder is separate fromTransitionSequencePlayer.OnCompleteevent. The builder version is appended as a finalCallbacknode duringBuild(), while the player event fires externally after sequence completion.
After animating, you may want to revert inline style overrides back to USS-defined or default values. Use ClearInlineStyles with the StyleProperty enum for type-safe cleanup:
var sequence = new TransitionSequence()
.Scale(1.2f, 0.2f)
.Scale(1f, 0.2f)
.ClearInlineStyles(StyleProperty.Scale)
.Build();
// Clear multiple properties at once
var sequence2 = new TransitionSequence()
.Together(sub => sub
.Scale(1.2f, 0.3f)
.Opacity(0.5f, 0.3f)
)
.Together(sub => sub
.Scale(1f, 0.3f)
.Opacity(1f, 0.3f)
)
.ClearInlineStyles(StyleProperty.Scale, StyleProperty.Opacity)
.Build();| Value | CSS Property |
|---|---|
Translate | translate |
Scale | scale |
Opacity | opacity |
Rotate | rotate |
BackgroundColor | background-color |
Width | width |
Height | height |
Color | color |
A string-based overload is also available for properties not covered by the enum:
.ClearInlineStyles("border-width", "margin-left")var sequence = new TransitionSequence()
.Scale(1.1f, 0.2f)
.Scale(1f, 0.2f)
.WithPlayMode(TransitionPlayMode.Loop) // Loop forever
.Build();
// Or loop a specific number of times
var sequence = new TransitionSequence()
.Rotate(360f, 1f)
.WithPlayMode(TransitionPlayMode.LoopCount)
.WithLoopCount(3) // Rotate 3 times
.Build();Animate multiple properties with shared timing:
var timing = new TransitionTimingConfig(0.3f, EasingMode.EaseOutBack);
var sequence = new TransitionSequence()
.Multi(timing,
new OpacitySetter(1f),
new ScaleSetter(new Vector2(1f, 1f)),
new TranslateSetter(Translate.None())
)
.Build();The TransitionSequence builder includes built-in preset methods for the most common animations. These are chainable and handle setup/cleanup internally (e.g. clearing inline styles).
Scales up past target, settles, dips below, then returns to 1. Each phase has its own duration for fine-tuned timing. Clears inline scale automatically.
var sequence = new TransitionSequence()
.Bounce(peakScale: 1.2f, settleScale: 1.15f, dipScale: 0.95f,
peakTime: 0.12f, settleTime: 0.1f,
holdTime: 0.2f,
dipTime: 0.08f, returnTime: 0.1f)
.Build();| Parameter | Type | Default | Description |
|---|---|---|---|
peakScale | float | 1.2 | Scale peak |
settleScale | float | 1.15 | Scale after peak, before dip. Set equal to peakScale to skip |
dipScale | float | 0.95 | Scale dip below 1 |
peakTime | float | 0.12 | Duration of the initial scale-up in seconds |
settleTime | float | 0.1 | Duration of the settle step in seconds |
holdTime | float | 0 | Optional pause after settle before scale-down begins. 0 = no pause |
dipTime | float | 0.08 | Duration of the dip step in seconds |
returnTime | float | 0.1 | Duration of the return-to-normal step in seconds |
easing | EasingMode | EaseOut | Easing for all scale steps |
// Instantly sets opacity to 0, then animates to 1
new TransitionSequence().FadeIn(duration: 0.3f).Build();
// Animates opacity to 0
new TransitionSequence().FadeOut(duration: 0.3f).Build();Animates translation from/to an offset. SlideIn clears inline translate at the end.
// Slide in from the left by 50px
new TransitionSequence()
.SlideIn(distancePx: 50f, direction: SlideDirection.Left, duration: 0.3f)
.Build();
// Slide out to the right by 80px
new TransitionSequence()
.SlideOut(distancePx: 80f, direction: SlideDirection.Right, duration: 0.3f)
.Build();SlideDirection values: Left, Right, Top, Bottom.
Scales up then back to 1, repeated count times. Clears inline scale at the end.
new TransitionSequence()
.Pulse(scale: 1.1f, duration: 0.15f, count: 2)
.Build();Presets are regular builder methods — chain them with any other step:
var sequence = new TransitionSequence()
.FadeIn(duration: 0.3f)
.SlideIn(distancePx: 30f, direction: SlideDirection.Bottom)
.Bounce()
.OnComplete(() => Debug.Log("Entrance complete!"))
.Build();Luna includes 52 ready-to-use animation presets organized into categories:
| Preset | Description |
|---|---|
| FadeIn / FadeOut | Opacity transitions |
| ScaleIn / ScaleOut | Scale from/to zero |
| SlideInUp/Down/Left/Right | Slide from off-screen |
| SlideOutUp/Down/Left/Right | Slide to off-screen |
| FlipIn / FlipOut | 3D flip effect via scaleX |
| RotateIn / RotateOut | Rotation with opacity |
| BounceIn | Bouncy scale entrance |
| Preset | Description |
|---|---|
| Shake / ShakeVertical | Horizontal/vertical shaking |
| Wobble | Rotation wobble |
| Jello | Elastic jiggle effect |
| Rubber | Rubber band stretch |
| Flash | Rapid opacity flashes |
| Heartbeat | Pulsing scale |
| ColorPulse | Background color pulse |
| Preset | Description |
|---|---|
| Pop | Quick scale bump |
| PopBounceIn / PopBounceOut | Bouncy pop entrance/exit |
| Press | Button press effect |
| Lift / LiftReset | Hover lift effect |
| Squish | Squash and stretch |
| Preset | Description |
|---|---|
| Spin | Continuous rotation |
| Bounce | Vertical bounce |
| Blink | Opacity blink |
| Breathe | Gentle scale pulse |
| Preset | Description |
|---|---|
| ZoomIn / ZoomOut | Scale with opacity |
| RiseIn / RiseOut | Rise from bottom |
| DropIn | Drop from top with bounce |
| SwingIn / SwingOut | Rotation swing |
| FoldY / UnfoldY | Vertical fold effect |
| Preset | Description |
|---|---|
| SlideInTop / SlideInBottom | Notification slide in |
| SlideOutTop / SlideOutBottom | Notification slide out |
| Preset | Description |
|---|---|
| PushInLeft / PushInRight | Page push entrance |
| PushOutLeft / PushOutRight | Page push exit |
UIViews can automatically play transition animations on fade events. See UIView Transitions for details.
// Add transition to UIView
myUIView.AddTransition(new UIViewTransitionEntry
{
Animation = popBounceInAsset,
Trigger = FadeEventTrigger.FadeInStart,
ElementName = "modal-content"
});Encapsulates timing configuration for transitions:
var timing = new TransitionTimingConfig(
duration: 0.3f, // Duration in seconds
easing: EasingMode.EaseOut, // Easing function
delay: 0.1f // Delay before start
);All Unity UI Toolkit easing modes are supported:
LinearEase, EaseIn, EaseOut, EaseInOutEaseInSine, EaseOutSine, EaseInOutSineEaseInQuad, EaseOutQuad, EaseInOutQuadEaseInCubic, EaseOutCubic, EaseInOutCubicEaseInCirc, EaseOutCirc, EaseInOutCircEaseInElastic, EaseOutElastic, EaseInOutElasticEaseInBack, EaseOutBack, EaseInOutBackEaseInBounce, EaseOutBounce, EaseInOutBouncepublic class ButtonHoverEffect : MonoBehaviour
{
[SerializeField] private TransitionSequenceAsset _hoverIn;
[SerializeField] private TransitionSequenceAsset _hoverOut;
private UIDocument _doc;
private TransitionSequencePlayer _playerIn;
private TransitionSequencePlayer _playerOut;
private VisualElement _button;
void Start()
{
_doc = GetComponent<UIDocument>();
_button = _doc.rootVisualElement.Q<Button>("my-button");
_playerIn = _hoverIn.CreatePlayer();
_playerOut = _hoverOut.CreatePlayer();
_button.RegisterCallback<PointerEnterEvent>(e =>
{
_playerOut.Stop();
_playerIn.Play(_button);
});
_button.RegisterCallback<PointerLeaveEvent>(e =>
{
_playerIn.Stop();
_playerOut.Play(_button);
});
}
}// Create a continuous spinning animation
var spinSequence = new TransitionSequence()
.Rotate(360f, 1f, EasingMode.Linear)
.WithPlayMode(TransitionPlayMode.Loop)
.Build();
var spinner = new TransitionSequencePlayer(spinSequence);
spinner.Play(loadingIcon);
// Stop when loading completes
spinner.Stop();The Components sample includes four demo scenes:
Repeat), color cascade, wave loader, and a grand finaleFadeIn, FadeOut, Bounce, SlideIn, SlideOut, Pulse) with a combo chain example and cascading staggerImport the Components sample to explore these demos.
Settings
Theme
Light
Contrast
Material
Dark
Dim
Material Dark
System
Sidebar(Light & Contrast only)
Font Family
DM Sans
Wix
Inclusive Sans
AR One Sans
Direction