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.

Transition Animations

Features

  • Declarative Animations: Define animations in ScriptableObjects for easy reuse
  • Fluent Builder API: Create animations in code with chainable methods
  • 52 Preset Animations: Ready-to-use animations across 7 categories
  • Code-Based Presets: Built-in .Bounce(), .FadeIn(), .FadeOut(), .SlideIn(), .SlideOut(), .Pulse() methods on the builder
  • UIView Integration: Automatic animation triggers on fade events
  • Play Modes: Once, Loop, PingPong, and LoopCount
  • Parallel & Sequential: Combine animations to run together or in sequence
  • Repeat: Loop a group of steps a fixed number of times within a sequence
  • OnComplete Callback: Register a callback on the builder that fires after the last node
  • Auto-Cancel: Playing a new animation on an element automatically stops any previous animation on that element
  • ClearInlineStyles: Revert inline style overrides after animations using StyleProperty enum
  • PlayOverlay: Fire UI particles/VFX at specific points in a sequence via PlayOverlay / PlayOverlayInstance nodes, with automatic handle cleanup

Quick Start

Using TransitionAnimator (MonoBehaviour)

The simplest way to add animations is through the TransitionAnimator component:

  1. Add TransitionAnimator to a GameObject
  2. Reference a UIDocument or UIViewComponent
  3. Add animation nodes (preset assets or inline step groups)
  4. Set play mode and trigger options
csharp
// Play animation manually transitionAnimator.Play(); // Or enable "Play On Enable" in the Inspector

Using Preset Assets

Luna includes 52 preset animation assets. Simply reference them in the TransitionAnimator:

csharp
// Load and play a preset directly TransitionSequenceAsset fadeIn = Resources.Load<TransitionSequenceAsset>("TransitionPresets/Base/FadeIn"); var player = fadeIn.CreatePlayer(); player.Play(myElement);

Using the Fluent API

Build animations programmatically with the TransitionSequence builder:

csharp
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);

Components

TransitionAnimator

MonoBehaviour that plays transition animations on VisualElements.

Inspector Properties

PropertyDescription
NodesOrdered list of animation nodes (inline step groups or sub-sequence asset references)
Play ModeOnce, Loop, PingPong, or LoopCount
Loop CountNumber of loops when Play Mode is LoopCount
UI View ComponentOptional UIViewComponent reference for target resolution
UI DocumentUIDocument reference (used when no UIViewComponent is set)
Element NameName of the target VisualElement (leave empty for root)
Fade TriggerWhich UIView fade event triggers this animation
Play On EnableAutomatically play when the component is enabled

Public Methods

csharp
// 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()

Events

csharp
UnityEvent OnComplete; // Fired when animation completes UnityEvent OnStopped; // Fired when animation is stopped

TransitionSequenceAsset

ScriptableObject for defining reusable animation sequences. Create via: Create > CupkekGames > Luna > Transition Sequence

Supports:

  • Inline step groups (sequential or parallel)
  • Sub-sequence references (composition)
  • Repeat nodes (loop inner nodes N times)
  • Overlay nodes (fire PlayOverlay / PlayOverlayInstance at a specific timing)
  • Recursive sub-sequence inlining with cycle detection

TransitionSequencePlayer

Runtime player for executing transition sequences on a VisualElement.

csharp
// 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;

Auto-Cancel

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:

csharp
var player1 = new TransitionSequencePlayer(bounceSequence); var player2 = new TransitionSequencePlayer(fadeSequence); player1.Play(myElement); // starts playing player2.Play(myElement); // automatically stops player1, then starts player2

Events

csharp
event Action OnComplete; // Sequence fully complete event Action<int> OnIterationComplete; // After each loop pass event Action OnStopped; // Playback stopped via Stop()

TransitionSequence Builder

The TransitionSequence class provides a fluent API for building animations:

Style Animations

csharp
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();

Parallel Animations

Run multiple animations simultaneously:

csharp
var sequence = new TransitionSequence() .Together(sub => sub .Opacity(1f, 0.3f) .Scale(1f, 0.3f) .Translate(0f, 0f, 0.3f) ) .Build();

Delays and Callbacks

csharp
var sequence = new TransitionSequence() .Opacity(0f, 0.3f) .Delay(0.5f) // Wait 500ms .Callback(() => Debug.Log("Halfway done!")) .Opacity(1f, 0.3f) .Build();

Repeat

Repeat a group of steps a fixed number of times:

csharp
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.

PlayOverlay (UI Particles / VFX)

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:

csharp
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:

csharp
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:

csharp
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:

csharp
var sequence = new TransitionSequence() .PlayOverlayInstance(existingParticleSystem) .Build();

Target a child element instead of the sequence root:

csharp
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:

  • Content — prefab (or scene instance if "Use Instance" is checked)
  • Render Settings — camera/resolution settings for the render-to-texture
  • Overlay Settings — anchor, width/height percentages, overflow visible
  • Target Element Name — optional child element to overlay onto (empty = sequence target)
  • Wait For Drain — when checked, blocks the sequence until the overlay finishes

Handle cleanup: Overlay handles are automatically tracked by TransitionSequencePlayer and released when the player is stopped, reset, or loops. You don't need to manage handle lifetimes manually.

OnComplete

Register a completion callback directly on the builder. It fires after all other nodes:

csharp
var sequence = new TransitionSequence() .FadeIn() .Bounce() .OnComplete(() => Debug.Log("All done!")) .Build();

Note: .OnComplete() on the builder is separate from TransitionSequencePlayer.OnComplete event. The builder version is appended as a final Callback node during Build(), while the player event fires externally after sequence completion.

ClearInlineStyles

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:

csharp
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();

StyleProperty Enum

ValueCSS Property
Translatetranslate
Scalescale
Opacityopacity
Rotaterotate
BackgroundColorbackground-color
Widthwidth
Heightheight
Colorcolor

A string-based overload is also available for properties not covered by the enum:

csharp
.ClearInlineStyles("border-width", "margin-left")

Play Modes

csharp
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();

Multi-Property Animation

Animate multiple properties with shared timing:

csharp
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();

Code-Based Presets

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).

Bounce

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.

csharp
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();
ParameterTypeDefaultDescription
peakScalefloat1.2Scale peak
settleScalefloat1.15Scale after peak, before dip. Set equal to peakScale to skip
dipScalefloat0.95Scale dip below 1
peakTimefloat0.12Duration of the initial scale-up in seconds
settleTimefloat0.1Duration of the settle step in seconds
holdTimefloat0Optional pause after settle before scale-down begins. 0 = no pause
dipTimefloat0.08Duration of the dip step in seconds
returnTimefloat0.1Duration of the return-to-normal step in seconds
easingEasingModeEaseOutEasing for all scale steps

FadeIn / FadeOut

csharp
// 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();

SlideIn / SlideOut

Animates translation from/to an offset. SlideIn clears inline translate at the end.

csharp
// 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.

Pulse

Scales up then back to 1, repeated count times. Clears inline scale at the end.

csharp
new TransitionSequence() .Pulse(scale: 1.1f, duration: 0.15f, count: 2) .Build();

Chaining Presets

Presets are regular builder methods — chain them with any other step:

csharp
var sequence = new TransitionSequence() .FadeIn(duration: 0.3f) .SlideIn(distancePx: 30f, direction: SlideDirection.Bottom) .Bounce() .OnComplete(() => Debug.Log("Entrance complete!")) .Build();

Preset Animations Library

Luna includes 52 ready-to-use animation presets organized into categories:

Base (17 presets)

PresetDescription
FadeIn / FadeOutOpacity transitions
ScaleIn / ScaleOutScale from/to zero
SlideInUp/Down/Left/RightSlide from off-screen
SlideOutUp/Down/Left/RightSlide to off-screen
FlipIn / FlipOut3D flip effect via scaleX
RotateIn / RotateOutRotation with opacity
BounceInBouncy scale entrance

Attention (8 presets)

PresetDescription
Shake / ShakeVerticalHorizontal/vertical shaking
WobbleRotation wobble
JelloElastic jiggle effect
RubberRubber band stretch
FlashRapid opacity flashes
HeartbeatPulsing scale
ColorPulseBackground color pulse

Feedback (7 presets)

PresetDescription
PopQuick scale bump
PopBounceIn / PopBounceOutBouncy pop entrance/exit
PressButton press effect
Lift / LiftResetHover lift effect
SquishSquash and stretch

Loading (4 presets)

PresetDescription
SpinContinuous rotation
BounceVertical bounce
BlinkOpacity blink
BreatheGentle scale pulse

Modals (9 presets)

PresetDescription
ZoomIn / ZoomOutScale with opacity
RiseIn / RiseOutRise from bottom
DropInDrop from top with bounce
SwingIn / SwingOutRotation swing
FoldY / UnfoldYVertical fold effect

Notifications (4 presets)

PresetDescription
SlideInTop / SlideInBottomNotification slide in
SlideOutTop / SlideOutBottomNotification slide out

Transitions (4 presets)

PresetDescription
PushInLeft / PushInRightPage push entrance
PushOutLeft / PushOutRightPage push exit

UIView Integration

UIViews can automatically play transition animations on fade events. See UIView Transitions for details.

csharp
// Add transition to UIView myUIView.AddTransition(new UIViewTransitionEntry { Animation = popBounceInAsset, Trigger = FadeEventTrigger.FadeInStart, ElementName = "modal-content" });

TransitionTimingConfig

Encapsulates timing configuration for transitions:

csharp
var timing = new TransitionTimingConfig( duration: 0.3f, // Duration in seconds easing: EasingMode.EaseOut, // Easing function delay: 0.1f // Delay before start );

Available Easing Modes

All Unity UI Toolkit easing modes are supported:

  • Linear
  • Ease, EaseIn, EaseOut, EaseInOut
  • EaseInSine, EaseOutSine, EaseInOutSine
  • EaseInQuad, EaseOutQuad, EaseInOutQuad
  • EaseInCubic, EaseOutCubic, EaseInOutCubic
  • EaseInCirc, EaseOutCirc, EaseInOutCirc
  • EaseInElastic, EaseOutElastic, EaseInOutElastic
  • EaseInBack, EaseOutBack, EaseInOutBack
  • EaseInBounce, EaseOutBounce, EaseInOutBounce

Example: Button Hover Effect

csharp
public 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); }); } }

Example: Loading Spinner

csharp
// 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();

Demo Scenes

The Components sample includes four demo scenes:

  • TransitionAnimationDemo: Interactive demo showcasing staggered cards, toast notifications, elastic bounce (using Repeat), color cascade, wave loader, and a grand finale
  • TransitionPresetGallery: Visual gallery of all 52 preset ScriptableObject animations
  • TransitionPresetCodeDemo: Standalone demo for code-based presets (FadeIn, FadeOut, Bounce, SlideIn, SlideOut, Pulse) with a combo chain example and cascading stagger
  • UIViewTransitionDemo: Demonstrates UIView fade event integration

Import the Components sample to explore these demos.

Settings

Theme

Light

Contrast

Material

Dark

Dim

Material Dark

System

Sidebar(Light & Contrast only)

Light
Dark

Font Family

DM Sans

Wix

Inclusive Sans

AR One Sans

Direction

LTR
RTL