A lightweight screen manager for hand-built uGUI interfaces in Unity. Screens are regular prefabs or scene objects with a UIScreen component; the package handles opening, closing, transitions, and optional on-demand loading through Addressables with predictive prefetching.
Note: parts of this documentation were written with the help of an AI assistant.
- One entry point —
UIRootroutes every request by key, so calling code does not care whether a screen sits in the scene or is loaded on demand. - Scene screens — register screens placed in a scene and open them by a typed key.
- Addressable screens — load screen prefabs on demand, keep a bounded cache, and prefetch the screens the player is most likely to open next.
- Typed keys —
ScreenIdreplaces enums; aScreensclass is generated from the catalog, so adding a screen never requires editing the package. - Transitions — fade and modal scale animations driven by unscaled time, so menus animate while the game is paused. Timing and curves come from a reusable
ScreenTransitionProfileasset;UIMotion.ReduceMotionturns animation off globally. - Inspector bindings — hook buttons to open or close a screen without writing code.
- Tests — EditMode and PlayMode test suites cover keys, ranking, code generation, loading, and navigation.
| Dependency | Version |
|---|---|
| Unity | 6000.0 or newer |
uGUI (com.unity.ugui) |
2.0.0 |
Addressables (com.unity.addressables) |
2.7.6 |
- Open Window → Package Manager.
- Click + and choose Add package from git URL...
- Paste:
https://github.com/alpershin/SimpleUIScreensSystem.git - Click Add. The Demo sample can be imported from the package page.
- Build a screen under a Canvas and add
UIScreento its root (aCanvasGroupis added automatically). - Fill in the ID field, assign close buttons, an optional modal container, and enable the animation if you want it. To tune timing and curves, create Create → Simple UI → Screen Transition Profile and assign it to the Transition field; screens without a profile use built-in defaults.
- Declare the key in your project and open the screen through the navigator:
using SimpleUIScreensSystem;
public static class Screens
{
public static readonly ScreenId Settings = new ScreenId("settings");
}
UINavigator.Instance.Open(Screens.Settings);
UINavigator.Instance.Close(Screens.Settings);UIInitializer finds every UIScreen on startup, registers it under its ID, and hides it.
UIRoot is the component your game talks to. It holds an ordered list of screen sources and sends each request to the first one that owns the key:
[SerializeField] private UIRoot _ui;
_ui.Open(Screens.Settings); // a scene screen or an Addressable one, same call
_ui.Close(Screens.Settings);
_ui.CloseAll();Add UIRoot to an active object, drag any IScreenSource components (such as AddressableUIRoot) into its Sources list, and leave Include Scene Screens on so keys registered with UINavigator are served too. Sources can also be registered from code with AddSource. Implement IScreenSource yourself to add a source of your own, for example screens loaded from an asset bundle or built at runtime.
AddressableUIRoot loads screen prefabs on demand and prefetches likely next screens in the background. Ranking combines a designer priority, decaying open frequency, learned screen-to-screen transitions, and recent user actions reported through ReportAction(). User requests always get a reserved load slot; the cache is bounded by screen count and an estimated memory budget.
- Mark the screen prefab as Addressable.
- Create Create → Simple UI → Addressable Screen Catalog and add an entry per screen: a Code Name (for example
Settings), the prefab reference, priority, memory estimate, and whether it may be prefetched. A stable ID is generated automatically and survives renames and prefab replacement. - Click Generate Screen Keys... in the catalog inspector and save the file inside your game's
Assetsfolder. - Add
AddressableUIRootto an active object, assign the catalog and a parent container under your Canvas.
using SimpleUIScreensSystem.AddressableUI;
using Game.UI; // namespace of the generated Screens class
[SerializeField] private AddressableUIRoot _navigator;
_navigator.ReportAction("inventory.tab_selected");
_navigator.Open(Screens.Inventory);
_navigator.Close(Screens.Inventory);For buttons, add AddressableScreenActions, pick the screen from the dropdown, and bind its Open or Close to the button's onClick.
Setup details, the ranking formula, defaults, lifecycle contract, and limitations are described in Documentation~/addressable-screen-cache.md (currently in Russian).
Base component for every screen. Can be used as is or subclassed.
Open()/Close()— start the opening or closing transition; calling the opposite mid-transition reverses it from the current values.Hide()— deactivates immediately without a transition.State—Hidden,Opening,OpenorClosing;IsOpenis true in every state butHidden.OnOpening,OnOpened,OnClosing,OnClosed—UnityEvents raised at the start and end of each transition. Activating or deactivating the object from outside raises them too.Init()— binds the transition; runs automatically inAwakewhen nobody called it earlier.Id— the typed key from the ID field.
Registry for scene screens, available as UINavigator.Instance or as a standalone instance.
Add(UIScreen)/Remove(UIScreen)Open(ScreenId, Action closeCallback = null)— the callback fires once when that opening closes.Close(ScreenId),CloseAll()TryGetScreen(ScreenId, out UIScreen)
Routing facade over one or more IScreenSource implementations.
Open(ScreenId),Close(ScreenId),CloseAll()Contains(ScreenId),TryGetScreen(ScreenId, out UIScreen),TryResolve(ScreenId, out IScreenSource)AddSource(IScreenSource)/RemoveSource(IScreenSource),SourcesScreenOpened— forwarded from every registered source while the root is enabled.
Keys no source owns raise an ArgumentException, so a typo in configuration fails loudly instead of silently doing nothing.
Scene-owned cache for Addressable screens.
Open(ScreenId),Close(ScreenId)— closing also cancels a pending open.ReportAction(string)— feeds the popularity model with a stable action name.TryGetScreen(ScreenId, out UIScreen),TrimCache()ScreenOpened,LoadFailed— events for activation and load errors.
ScreenTransitionProfile is a ScriptableObject with the fade duration, fade curve, modal hidden scale, and scale curve. Assign one per screen or share it across screens. UIMotion.ReduceMotion is a process-wide switch that makes every screen open and close instantly; set it from your settings screen or from platform accessibility preferences.
Immutable value type with ordinal comparison. Keys are case-sensitive; default(ScreenId) is invalid and is rejected by both navigators.
EScreenTypewas removed. Set the ID field on each sceneUIScreenand declareScreenIdconstants in your project.UINavigator.Open(EScreenType.X)→Open(Screens.X);GetScreen→TryGetScreen.OnOpenednow fires when the opening transition has finished, not when the object is activated; subscribe toOnOpeningfor the old timing.- The shared
Coroutinesrunner is obsolete; transitions run on the screen itself. - The minimum Unity version is now 6000.0, and Addressables and uGUI are declared dependencies.
Open Window → General → Test Runner. EditMode suites cover ScreenId, the popularity policy, and key generation. PlayMode suites cover AddressableUIRoot with an in-memory resource provider and UINavigator; they do not require Addressables settings or a content build.
MIT. See LICENSE.
Open an issue in this repository if you run into problems or have questions.