skills/unity-app-ui-navigation/SKILL.md
Expert for App UI navigation system - NavGraph, NavHost, NavController, destinations, and visual controllers (AppBar, Drawer, BottomNavBar). Use this skill whenever the user wants to add screens or pages to their Unity app, create a navigation graph, set up a bottom tab bar, implement a side drawer or hamburger menu, add an app bar or toolbar, navigate between views, pass data between screens, manage back stack behavior, create a multi-screen flow (onboarding, login, settings), or implement any kind of screen-to-screen navigation in App UI. Also trigger when the user mentions NavigationScreen, NavigationRail, NavAction, or asks about deep linking or nested navigation.
npx skillsauth add cuozg/oh-my-skills unity-app-ui-navigationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Expert assistant for implementing navigation systems in Unity using the App UI framework. Specializes in NavGraph construction, NavHost setup, NavController usage, and visual navigation component control.
The App UI navigation system consists of these key components:
A NavGraph MUST have a start destination. This is the first page shown:
// CORRECT: Set start destination
navGraph.startDestination = homeDestination;
// WRONG: Missing start destination causes runtime errors
Control navigation UI components through a single controller:
class MyNavVisualController : INavVisualController
{
public void SetupAppBar(AppBar appBar, NavDestination destination, NavController navController)
{
appBar.title = destination.label;
}
public void SetupDrawer(Drawer drawer, NavDestination destination, NavController navController)
{
// Populate drawer
}
public void SetupBottomNavBar(BottomNavBar bottomNavBar, NavDestination destination, NavController navController)
{
// Populate bottom nav bar
}
public void SetupNavigationRail(NavigationRail navigationRail, NavDestination destination, NavController navController)
{
// Populate navigation rail
}
}
Global actions work from any destination, local actions only from specific sources:
// CORRECT: Global action for logout (available everywhere)
var logoutAction = new NavAction { actionId = "logout", destination = loginGraph.startDestination };
navGraph.globalActions.Add(logoutAction);
// CORRECT: Local action (only from home)
var settingsAction = new NavAction { actionId = "openSettings", source = homeDestination, destination = settingsDestination };
navGraph.actions.Add(settingsAction);
The DefaultDestinationTemplate handles NavigationScreen instantiation and visual component setup:
var destination = new NavDestination
{
label = "Home",
name = "home",
template = new DefaultDestinationTemplate
{
screenType = typeof(HomeScreen),
showAppBar = true,
showDrawer = true,
showBottomNavBar = true
}
};
Pass data to destinations using the Argument array:
// Navigate with arguments
navController.Navigate("details", new[] {
new Argument { key = "id", value = 123 }
});
// Receive arguments in NavigationScreen
public class DetailsScreen : NavigationScreen
{
public override void OnEnter(NavController controller, NavDestination destination, Argument[] args)
{
var id = args.First(a => a.key == "id").value;
}
}
Control back stack behavior through NavAction properties:
var action = new NavAction
{
actionId = "navigateToHome",
destination = homeDestination,
// Clear back stack when navigating home
backStackBehavior = BackStackBehavior.ClearStack
};
public void SetupAppBar(AppBar appBar, NavDestination destination, NavController navController)
{
appBar.title = destination.label;
// Add action buttons
var editButton = new ActionButton { icon = "edit", label = "Edit" };
editButton.clickable.clicked += () => navController.Navigate("editScreen");
appBar.Add(editButton);
}
public void SetupDrawer(Drawer drawer, NavDestination destination, NavController navController)
{
drawer.Add(new DrawerHeader { title = "Navigation" });
drawer.Add(new Divider { vertical = false });
var homeItem = new MenuItem { icon = "home", label = "Home", selectable = true };
homeItem.SetValueWithoutNotify(destination.name == "home");
homeItem.clickable.clicked += () => navController.Navigate("home");
drawer.Add(homeItem);
var settingsItem = new MenuItem { icon = "settings", label = "Settings", selectable = true };
settingsItem.SetValueWithoutNotify(destination.name == "settings");
settingsItem.clickable.clicked += () => navController.Navigate("settings");
drawer.Add(settingsItem);
}
public void SetupBottomNavBar(BottomNavBar bottomNavBar, NavDestination destination, NavController navController)
{
var homeItem = new BottomNavBarItem("home", "Home", () => navController.Navigate("home"))
{
isSelected = destination.name == "home"
};
bottomNavBar.Add(homeItem);
var exploreItem = new BottomNavBarItem("explore", "Explore", () => navController.Navigate("explore"))
{
isSelected = destination.name == "explore"
};
bottomNavBar.Add(exploreItem);
}
public void SetupNavigationRail(NavigationRail navigationRail, NavDestination destination, NavController navController)
{
navigationRail.anchor = NavigationRailAnchor.Start;
navigationRail.labelType = LabelType.Selected;
var homeItem = new NavigationRailItem { icon = "home", label = "Home", selected = destination.name == "home" };
homeItem.clickable.clicked += () => navController.Navigate("home");
navigationRail.mainContainer.Add(homeItem);
var settingsItem = new NavigationRailItem { icon = "settings", label = "Settings", selected = destination.name == "settings" };
settingsItem.clickable.clicked += () => navController.Navigate("settings");
navigationRail.mainContainer.Add(settingsItem);
}
public class HomeScreen : NavigationScreen
{
protected override void SetupAppBar(AppBar appBar, NavController navController)
{
appBar.title = "Home";
var menuButton = new ActionButton { icon = "menu", label = "Menu" };
menuButton.clickable.clicked += () => navController.Navigate("settings");
appBar.Add(menuButton);
}
}
// Main graph with embedded settings graph
var mainGraph = new NavGraph { name = "main", startDestination = homeDestination };
mainGraph.destinations.Add(homeDestination);
var settingsGraph = new NavGraph { name = "settings", startDestination = settingsHomeDestination };
settingsGraph.destinations.Add(settingsHomeDestination);
// Navigate to nested graph
navController.Navigate("settings");
public class MyAppBuilder : UIToolkitAppBuilder<MyApp>
{
protected override void OnConfiguringApp(AppBuilder builder)
{
base.OnConfiguringApp(builder);
// Setup navigation resources
var navGraphAsset = Resources.Load<NavGraphViewAsset>("Navigation/MyNavGraph");
builder.services.AddSingleton(navGraphAsset);
}
protected override void OnAppReady(MyApp app)
{
base.OnAppReady(app);
// Setup NavHost
var navHost = new NavHost();
navHost.visualController = new MyNavVisualController();
var navGraphAsset = app.GetService<NavGraphViewAsset>();
navHost.LoadGraph(navGraphAsset);
root.Add(navHost);
}
}
Use the Navigation Graph Editor's code generator to create strongly-typed constants:
// Generated code provides constants for all destinations, actions, and graphs
public partial static class Actions
{
public const string NavigateToHome = "navigateToHome";
public const string NavigateToSettings = "navigateToSettings";
}
public partial class Destinations
{
public const string Home = "home";
public const string Settings = "settings";
}
// Use constants to avoid typos
navController.Navigate(Destinations.Home);
Assets/Resources/Navigation/Assets/Scripts/Navigation/Screens/Assets/Scripts/Navigation/Controllers/Assets/Scripts/Navigation/Generated/ (created by code generator)Consult reference.md when you need exact API signatures for NavGraph, NavDestination, NavAction, NavController, or NavHost, full property lists, lifecycle event details, or advanced patterns like nested graph resolution and custom destination templates. See examples/ for complete working code samples.
tools
Generate Unity raster image assets through Unity MCP: game sprites, item art, backgrounds, UI icons, portraits, concept images, transparent cutouts, image edits, upscales, background removal, and Unity scene or Game View screenshots. Use when a Unity project needs image files imported under Assets or screenshots captured from the editor. Do not use for meshes, audio, animation, materials, gameplay code, UI Toolkit layout, or generic non-Unity image generation.
tools
Create Unity technical solution documents from user requirements, feature ideas, bug goals, specs, or codebase problems. Use when the user asks for a technical approach, architecture, implementation strategy, solution options, feasibility analysis, system design, or "how should we build/fix this" for Unity runtime, Editor, tools, assets, data, UI, WebGL, SDKs, or production pipelines.
tools
Orchestrate Unity Editor via MCP (Model Context Protocol) tools and resources. Use when working with Unity projects through MCP for Unity - creating/modifying GameObjects, editing scripts, managing scenes, running tests, or any Unity Editor automation. Provides best practices, tool schemas, and workflow patterns for effective Unity-MCP integration.
development
Convert a spec document into an implementation TODO list in the same spec folder. U se when the user says goal-todo, todo from spec, generate tasks from spec, turn this spec into todos, create implementation checklist, extract tasks, or asks to read a Docs/Specs design doc and produce what must be implemented. Includes UI/UX review and codebase investigation before writing the checklist. Do not use for implementing the tasks, creating new goal files, writing test cases, or verifying completed work.