UI Toolkit: Screen Manager
Stack-based screen navigation for Unity UI Toolkit. Push, pop, replace screens with animated transitions, lifecycle hooks, back-stack management, and input blocking. Full source. Zero dependencies.
by KrookedLilly
Price History +
Unity 6 UI Toolkit ships with no concept of screens, pages, or navigation. You're left manually showing and hiding VisualElements, writing your own back-stack, and praying your transitions don't double-fire when two navigations land in the same frame.
This asset is the missing navigation layer. Stack-based push/pop/replace, six async lifecycle hooks per screen, five built-in transitions, automatic back-button handling, and deep-link navigation with synthetic back-stacks — all built on UI Toolkit's existing primitives, no separate canvas, no GameObject-per-screen.
One-line navigation.
await Manager.PushAsync("Gameplay");
await Manager.PopAsync();
await Manager.ReplaceAsync("MainMenu");
await Manager.PopToAsync("MainMenu");
await Manager.NavigateToAsync("ItemDetail", new[] { "MainMenu", "Shop" });
Every navigation call is async, returns a NavigationResult you can inspect, and respects the configured transition. Calls made during an active transition queue up and run sequentially — no double-tap navigation bugs, no race conditions in your menus.
Six async lifecycle hooks per screen.
OnScreenCreated (bind UXML once), OnScreenEnter (start animations, fetch data), OnScreenPause (a screen was pushed on top), OnScreenResume (returned to foreground), OnScreenExit (about to leave the stack), OnScreenDestroy (final cleanup). Every async hook receives a CancellationToken and is protected by a configurable timeout — no hung lifecycle hook can block navigation indefinitely.
Five built-in transitions, customizable per screen.
Fade, Slide (left / right / up / down with auto-reverse on pop), Scale, Crossfade, and None ship out of the box, driven by USS transition properties for GPU-accelerated smoothness. Duration and easing are per-screen in the Inspector; set a screen's transition to "Inherited" to fall through to the manager's default. Want something custom? Implement IScreenTransition or subclass ScreenTransitionBase and the custom transition type shows up in the Inspector dropdown automatically.
Back-button handling that just works.
UI Toolkit's NavigationCancelEvent maps Escape (desktop), the Android hardware back button, and gamepad B / Circle for you. Override OnBackPressed() on any screen and return true to consume the event — perfect for a "discard changes?" confirmation. The OnBackAtRoot event fires when the user presses back at the root screen, ready to be wired to a quit dialog. A transparent overlay automatically blocks pointer and navigation input during transitions, so nothing lands mid-animation.
Deep-link navigation with synthetic back-stacks.
Launch directly into any screen from a push notification, a daily-challenge URL, or startup logic. NavigateToAsync("ItemDetail", new[] { "MainMenu", "Shop" }) builds the intermediate stack silently — the user lands on ItemDetail with MainMenu and Shop already behind them, so pressing Back walks them through the path as if they had navigated there manually. Pass typed data along the way via NavigationOptions.Data and read it on the other side with TryGetNavigationData<T>().
History-aware screens and three preload modes.
Per-screen BackStackBehavior controls how each screen participates in back navigation: Standard (normal), SkipOnBack (in the stack but skipped on back — loading screens), or NoHistory (never added — splash screens, game-over screens). Per-screen ScreenLoadMode controls when each screen is instantiated: Lazy (on first navigation), Preload (at startup, with OnScreenCreated fired immediately for binding), or OnDemand (via explicit PreloadScreenAsync call).
Custom inspectors with live debugging.
The custom ScreenManager inspector shows the active screen, the full stack from bottom to top, transitioning status, and manual push / pop / replace controls while the game is running. The ScreenRegistry inspector validates every entry with a one-click "Validate All" button and surfaces inline warnings for missing UXML assets, duplicate IDs, or unknown screen types.
Two demo scenes included.
GameDemo — a five-screen game flow: a Main Menu with push navigation and a deep-link trigger, a Settings screen with toggle / slider controls and SkipOnBack behavior, a Gameplay HUD with a coin-catching mini-game (falling coins, click-to-score, health bar, game-over detection), a Pause Menu overlay using the Scale transition, and a Game Over screen with Replay (ReplaceAsync) and Main Menu (PopToRootAsync) buttons using NoHistory.
MacroTrackerDemo — a nutrition-tracker flow showing realistic data-driven screen navigation with typed data passing between screens. Both demos ship with controllers, UXML, USS, and configured panel settings; no external art dependencies, only built-in UI Toolkit styling.
Plays well with the rest of the UI Toolkit Components suite.
Open Tools > KrookedLilly > Setup to see every sibling that consumes from Screen Manager — Focus & Navigation, Modal & Notifications, Theme Switcher, Form Validation, Data Binding, ECS Bridge. Enable an integration to turn on that sibling's code; each one ships disabled by default so your project never picks up code from siblings you do not enable.
With UI Toolkit: Tween Engine — open Tools > KrookedLilly > Setup and enable the Tween Engine → Screen Manager integration. Four tween-driven IScreenTransition implementations (Fade, Slide, Scale, Crossfade) snap into Screen Manager's navigation system through TransitionProvider. Pick one per screen in the Inspector or set it as the default; the tween runtime takes over from the built-in CSS transitions. Without the toggle, Screen Manager continues to use its built-in CSS transitions.
Works on every platform.
Render-pipeline agnostic — runs under URP, HDRP, and the Built-in pipeline. Runs under Mono and IL2CPP scripting backends. Uses the standard Unity AOT path that ships on iOS, Android, WebGL, and consoles.
Full C# source, no DLLs.
XML documentation on every public API. Zero external dependencies — only the com.unity.modules.uielements module is required.