Skip to content

Build your first Tick UI screen

A guided walk-through of building a small but realistic screen from scratch. By the end, you have a working settings panel with a heading, a scrollable list of toggle rows, hover animations, and a modal confirmation dialog.

Tutorials are learning-oriented. This page walks through the steps in order; each step builds on the previous one. If you want the procedural recipe for a single feature, read the matching task page instead.

What you need

Before starting, complete:

  • Install Tick UI.
  • Set up Tick UI. The tutorial assumes you have a MyGameUI MonoBehaviour with an empty DoUI body, attached to a GameObject with the URP or BIRP injector wired.

The finished screen looks like a centred dark panel with a heading at the top, three toggle rows in the middle, and an Apply button at the bottom. Clicking Apply opens a confirmation modal.

Step 1: draw the panel background

Open MyGameUI.cs and edit DoUI. Replace the body with:

protected override void DoUI(UI ui)
{
    ui.BeginFrame(new Vector2Int(Screen.width, Screen.height));
    ui.Fill(Color.clear);

    using (ui.Auto().Center(480, 360))
    {
        ui.FillRounded(UI.FromHex("#1A1A1A"), 12);
    }

    ui.EndFrame();
}

Press play. A centred dark rounded panel appears. The ui.Auto().Center(480, 360) scope pushes a centred rect; the FillRounded call fills it with a rounded background.

For the Auto() scope and the Center helper, refer to Layout.

Step 2: add a heading

Inside the Auto().Center(480, 360) scope, add a top strip with text:

using (ui.Auto().Top(48).PadHorizontal(20))
{
    ui.Text("Settings", "roboto_mono", 24, Color.white,
        TextAlign.MiddleLeft);
}

The Top(48) push gives a 48-pixel-tall strip at the top of the panel; PadHorizontal(20) insets it left and right by 20 pixels; Text renders the heading.

Press play. A Settings heading appears at the top of the panel.

Step 3: add a row of toggles

Below the heading, lay out three toggle rows. Use a series layout so the rows share equal height:

using (ui.Auto().Top(48).Bottom(56).Pad(20))
{
    ui.PushSeriesVertical(40, 8);
    {
        DrawToggleRow(ui, "Vsync");           ui.Next();
        DrawToggleRow(ui, "Show FPS");        ui.Next();
        DrawToggleRow(ui, "Reduced motion");
    }
    ui.Pop();
}

Top(48).Bottom(56) carves out the middle of the panel between the heading and the future Apply button; Pad(20) insets that middle area. PushSeriesVertical(40, 8) lays out three 40-pixel-tall rows with an 8-pixel gap.

Add a DrawToggleRow helper to the same MonoBehaviour:

private void DrawToggleRow(UI ui, string label)
{
    ui.FillRounded(UI.FromHex("#2A2A2A"), 5);
    using (ui.Auto().PadHorizontal(12))
    {
        ui.Text(label, "roboto_mono", 14, Color.white,
            TextAlign.MiddleLeft);
    }
}

Press play. The three rows appear stacked inside the panel.

For the schema layouts used here, refer to Schemas.

Step 4: animate the row hover

Add hover feedback by wrapping each row in a PushAnimate scope. Update DrawToggleRow:

private void DrawToggleRow(UI ui, string label)
{
    var ctx = ui.PushAnimate("row")
        .Init().Color().Set(UI.FromHex("#2A2A2A")).Done()
        .Enter().Color().Blend(UI.FromHex("#2A2A2A"),
                               UI.FromHex("#3A3A3A"), 0.15f).Done()
        .Leave().Color().Blend(UI.FromHex("#3A3A3A"),
                               UI.FromHex("#2A2A2A"), 0.15f).Done()
        .BoolWhileTrue("hover", ui.IsHovered())
        .Apply();

    ui.FillRounded(ctx.GetColor(), 5);
    using (ui.Auto().PadHorizontal(12))
    {
        ui.Text(label, "roboto_mono", 14, Color.white,
            TextAlign.MiddleLeft);
    }

    ui.PopAnimate();
}

Press play. Each row tints darker on hover and back on leave. At this point all three rows share the same context ID ("row"). Wrap the call site in PushID to give each row its own state:

ui.PushID("vsync");        DrawToggleRow(ui, "Vsync");        ui.PopID(); ui.Next();
ui.PushID("show_fps");     DrawToggleRow(ui, "Show FPS");     ui.PopID(); ui.Next();
ui.PushID("reduced_motion"); DrawToggleRow(ui, "Reduced motion"); ui.PopID();

For the identity model, refer to IDs. For the animation context lifecycle, refer to Animation.

Step 5: add an Apply button

Reserve the bottom 48 pixels of the panel for the button. Inside your existing Auto().Center(480, 360) scope:

using (ui.Auto().Bottom(48).PadHorizontal(20))
{
    ui.FillRounded(UI.FromHex("#23C9FF"), 5);
    ui.Text("Apply", "roboto_mono", 14, Color.white,
        TextAlign.MiddleCenter);

    if (ui.Button("apply"))
        ui.ShowModal("confirm_apply");
}

Press play. The blue button appears. Clicking it does nothing visible yet; the next step builds the confirmation modal.

For the visual-then-Button idiom, refer to Make a button.

Step 6: add a confirmation modal

Outside the Auto().Center(480, 360) scope (still inside DoUI, between BeginFrame and EndFrame), declare the modal:

if (ui.BeginPanel("confirm_apply", screenRect, new PanelConfig
{
    Hidden = true,
    BackdropColor = new Color(0, 0, 0, 0.75f),
}))
{
    using (ui.Auto().Center(320, 140))
    {
        ui.FillRounded(UI.FromHex("#1A1A1A"), 8);

        using (ui.Auto().Top(48).PadHorizontal(20))
        {
            ui.Text("Apply changes?", "roboto_mono", 16, Color.white,
                TextAlign.MiddleCenter);
        }

        using (ui.Auto().Bottom(40).PadHorizontal(20))
        using (ui.PushSplitHorizontal(2, 8))
        {
            using (ui.Auto())
            {
                ui.FillRounded(UI.FromHex("#2A2A2A"), 5);
                ui.Text("Cancel", "roboto_mono", 14, Color.white,
                    TextAlign.MiddleCenter);
                if (ui.Button("cancel"))
                    ui.HidePanel("confirm_apply");
            }

            ui.Next();

            using (ui.Auto())
            {
                ui.FillRounded(UI.FromHex("#23C9FF"), 5);
                ui.Text("Apply", "roboto_mono", 14, Color.white,
                    TextAlign.MiddleCenter);
                if (ui.Button("confirm"))
                {
                    ApplySettings();
                    ui.HidePanel("confirm_apply");
                }
            }
        }
    }

    ui.EndPanel();
}

Add a placeholder ApplySettings method that logs:

private void ApplySettings() { Debug.Log("Applied"); }

Press play. Click Apply on the main panel; the confirmation modal appears with a dimmed background. Cancel hides it; Apply logs and hides it.

For the modal pattern, refer to Show a modal. For the input-priority rules that make the modal block the panel below, refer to Input and focus.

What you built

A complete settings screen with a heading, three animated rows, an Apply button, and a confirmation modal. Roughly 80 lines of DoUI code.

You used:

Additional resources

  • Read the Concepts section for the model behind everything you used.
  • Browse the Gallery sample (Package Manager > Tick UI > Samples > Gallery) for more worked examples.
  • Add a scrollable list to your panel when you have more rows than fit.
  • Add a textbox for editable fields.