First View

Assumes you've finished Quick Start (you know the Panel Settings → TSS chain) and know what UXML, USS, and a VisualElement are (covered in UI Toolkit Basics).

This walkthrough does one thing on purpose: shows that Luna's theme applies itself to standard UITK controls the moment you point a UIDocument at LunaPanelSettings. The end state is a brand-new scene with a Luna-themed label + button you wired from C# — no extra USS, no extra prefab, just standard <Label> and <Button> picking up Luna's look automatically.

Before you build from scratch: Luna ships ready-made Views — Main Menu, Pause, Settings, Save & Load, Credits, Inventory, Dialogue. For full-screen flows, extending one of those is usually faster than authoring your own from zero. This page is the canonical "how do I write a custom view of my own?" walkthrough — useful either way, since extending a Luna view also means subclassing UIViewComponent.

1. Set up the scene

Create a fresh scene (File > New Scene > Empty).

You need three things in the scene:

  1. LunaUIManager — drag Assets/Samples/LunaUI/<version>/Essentials/Prefabs/LunaUIManager.prefab into the scene. This GameObject hosts the LunaUIManager component plus input wiring. Every view subscribes to it for focus management and input handling. See Luna UI Manager for what it does.
  2. EventSystem — add GameObject > UI > Event System if the scene doesn't have one yet. UI Toolkit input dispatch requires it.
  3. Your view GameObjectGameObject > UI > UI Document. This creates an empty GameObject with a UIDocument component on it.

⚠️ Naming warning. Unity uses the phrase "UI Document" for two different things: the component you just added to a scene GameObject (this step), and a .uxml asset you create from the Project window (step 2). They're not the same. From here on, this guide says "the UIDocument GameObject" for the scene object and "the .uxml file" for the asset.

Select the new UIDocument GameObject and fill its Inspector:

  • Panel Settings: drag Essentials/Theme/LunaPanelSettings.asset (screen-space) or LunaPanelSettingsWorldSpace.asset (world-space). This single reference is what wires Luna's full theme into your view — same chain you traced in Quick Start step 3. Anything you author from here on inherits the theme.
  • Source Asset: leave empty for now — you'll create a UXML file in step 2.

UI Document component Inspector with Panel Settings field filled and Source Asset empty

2. Create the UXML

Right-click in the Project view → Create > UI Toolkit > UI Document. Despite the menu wording, this creates a .uxml asset (a file in your project), not a scene GameObject. Name it MyView.uxml. Open it in UI Builder (double-click).

Add a VisualElement as a container, then drop in a Label and a Button from the Library panel. Give them names you can find from code:

  • Label → name: my-label, set text to "Hello, Luna"
  • Button → name: my-button, set text to "Click me"

About what you just added: <Label> and <Button> are standard Unity UI Toolkit controls — not Luna types. The Luna theme automatically styles every standard UITK control through the USS imported by LunaUIDemoTheme.tss. You'll see Luna's font, button colors, focus ring, hover state, and rounded corners apply without authoring any USS yourself. To use Luna's custom controls (ProgressBar, Tabview, RadialLoading, Tooltip, …), drop them in from the Library too — they live under the CupkekGames.Luna namespace and ship with the package.

Save the file. Back on your UIDocument GameObject in the scene, assign MyView.uxml to its Source Asset field — that's what connects the asset to the scene.

UI Builder showing MyView.uxml with a container holding a Label and Button

If you press Play now, the label and button render with the Luna theme already applied — but they don't do anything yet, and the view skips Luna's fade-in animation because nothing has wired UIViewComponent in.

3. Write the view script

Create Assets/Scripts/MyView.cs:

csharp
using CupkekGames.Luna; using UnityEngine; using UnityEngine.UIElements; public class MyView : UIViewComponent { private Label _label; private Button _button; private int _clicks; protected override void Awake() { base.Awake(); // ParentElement is the root VisualElement of the UIDocument // (or the named sub-element if you set _parentName on the component). _label = ParentElement.Q<Label>("my-label"); _button = ParentElement.Q<Button>("my-button"); } private void OnEnable() { // Unity's Button exposes a `clicked` Action — simpler than // RegisterCallback<ClickEvent>(...) for the common case. _button.clicked += OnClicked; } private void OnDisable() { _button.clicked -= OnClicked; } private void OnClicked() { _clicks++; _label.text = $"Hello, Luna ({_clicks} clicks)"; } }

Attach this script to the same GameObject as your UIDocument component — the GameObject from step 1, not the .uxml asset. Since MyView is a UIViewComponent subclass, adding it also adds the UIViewComponent plumbing automatically.

Inspector defaults you can leave as-is:

  • UIDocument (reference to the component on this GameObject) — auto-resolves from the same GameObject if left empty.
  • Parent Name — leave empty to use the UXML root; set to a VisualElement name to scope the view to a sub-tree.
  • Focus Name — element to focus when the view fades in (used for keyboard navigation).
  • Fade Duration / Easing Mode — fade-in animation. 0.5 / EaseOutCirc is the Luna default.
  • Start VisibilityFadeIn makes the view fade in on Awake.

Press Play. The view fades in (that's UIViewComponent doing it); the button increments the label on click; everything wears the Luna theme without a single line of USS in your project.

Running scene showing the Luna-themed button incrementing the label after several clicks

4. Add fade transitions

UIViewComponent exposes a Fade property — a FadeUIElement that animates opacity + interactability.

To fade the view out programmatically:

csharp
Fade.FadeOut();

To destroy the GameObject after the fade completes (the standard "close this view" flow):

csharp
FadeOutThenDestroy();

Subscribe to fade events for state-aware logic:

csharp
private void OnEnable() { Fade.OnFadeIn += OnFadedIn; Fade.OnFadeOut += OnFadedOut; } private void OnDisable() { Fade.OnFadeIn -= OnFadedIn; Fade.OnFadeOut -= OnFadedOut; } private void OnFadedIn() { /* view fully visible */ } private void OnFadedOut() { /* view fully hidden */ }

5. Wire it into navigation

For modal-style views that open on demand (e.g. an inventory popup):

For full-screen views that stack (Main Menu → Settings → Credits), see the Views section — Main Menu / Pause Menu / Settings / Save & Load are all pre-built UIViewComponent subclasses you can extend.

For a complete multi-page UI example with navigation, see Example: Multi Page UI.

What you just proved

The whole point of this walkthrough: Luna's theme is one Panel Settings reference away from any UXML you author. You didn't write any USS, didn't drag any prefab into your UXML, didn't subclass anything Luna-specific from your UXML side — and yet the result wears the Luna look, fades in on appear, hooks into focus management, and is ready to participate in navigation.

If you want richer UI without writing more code, the natural next moves are:

  • Pre-built viewsViews section covers Main Menu, Pause, Settings, Save & Load, Inventory, Credits, Dialogue. Most projects extend one of these instead of authoring from scratch.
  • Custom componentsComponents section has per-component pages for Luna's drop-in widgets: ProgressBar, RadialLoading, Tooltip, Tabview, PieChart, CooldownWipe, etc.
  • EffectsTransition Animation for entry/exit motion; UI Effects for glow / outline / shadow / gradient via USS.
  • UI ActionsUI Actions — a slot-based action system for view-level behaviors (escape handling, hotkey wiring).

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