Skip to content

Set up Tick UI

Create your first Tick UI screen. The procedure has four steps: subclass BaseGameUI, write a minimal DoUI body, attach the component to a GameObject, and configure the URP or BIRP injector in the Inspector. After this page, the Concepts section explains the model behind the API used.

This page assumes you have already installed Tick UI and read the Introduction to immediate-mode GUI.

Subclass BaseGameUI

BaseGameUI is the MonoBehaviour Tick UI provides for hosting a UI instance and running your draw code each frame. Subclass it and override DoUI(UI ui):

using UnityEngine;
using Interlude.Tick;

public class MyGameUI : BaseGameUI
{
    private int m_clickCount;

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

        using (ui.Auto().Center(240, 80))
        {
            ui.FillRounded(UI.FromHex("#23C9FF"), 8);
            ui.Text($"Clicks: {m_clickCount}", "roboto_mono", 24, Color.white,
                TextAlign.MiddleCenter);

            if (ui.Button("counter"))
                m_clickCount++;
        }

        ui.EndFrame();
    }
}

BaseGameUI handles Start (it creates the UI instance) and LateUpdate (it calls DoUI) for you. Override only DoUI, not Update or Start. For the per-frame phases that surround DoUI, refer to Frame lifecycle.

The example pairs the visual with a click counter on purpose: it shows the immediate-mode loop in one screen. Each frame DoUI reads m_clickCount and bakes it into the text. The if (ui.Button("counter")) call writes to the field on the frame of the click. Logic and rendering are the same call, scoped to the rect on top of the layout stack. Removing the increment freezes the count. Removing the Button line removes the hit-test, and the layout still renders.

To set up Tick UI in your scene

  1. Create an empty GameObject in the scene.
  2. Attach your MyGameUI component to the GameObject.
  3. Attach the render-pipeline injector to the same GameObject:

    • URP projects: TickURPInjector.
    • Built-in projects: TickBIRPInjector (the GameObject must also have a Camera component).

    The injector finds the recorder on the same GameObject via GetComponent<TickRecorder>(), so no Inspector wiring is needed. Keep MyGameUI and the injector together. 4. Press play.

A centred, rounded blue rect appears reading Clicks: 0. Click it, and the count goes up. The state lives on your MonoBehaviour (the m_clickCount field), and the UI re-reads it every frame.

For URP-specific and BIRP-specific configuration (render-pipeline asset settings, render-scale, camera-event ordering), refer to Configure URP and Configure BIRP.

Resource providers

BaseGameUI exposes a Resource Providers array in the Inspector. Add GUIResourceProvider assets to this array to register custom fonts, icons, or shaders. Index 0 is checked first; the bundled DefaultTickConfig is appended underneath as the lowest-priority fallback.

For the "Hello, world" example, the array can remain empty. The bundled default provides the roboto_mono font referenced in the snippet above. To register your own fonts, refer to Add a custom font. For the model behind the chain, refer to Resource providers.

Common pitfalls

DoUI doesn't run. : The MyGameUI component is missing from the scene, or the GameObject is disabled. Check the scene hierarchy.

Nothing renders. : MyGameUI and the injector are on different GameObjects, or the URP project doesn't have TICK_URP defined. The URP and BIRP injectors find the recorder via GetComponent<TickRecorder>() on the same GameObject. Keep them together. For URP, also verify the define under Project Settings > Player > Scripting Define Symbols.

Pink materials. : The resource provider chain is missing the bundled DefaultTickConfig. The standard BaseGameUI flow handles this for you, so a missing default usually means a custom CreateUI override skipped the bundled append. Refer to Resource providers.

UI scales wrong on resolution change. : The per-frame scale cache refreshes inside BeginFrame from Screen.width/Screen.height. Confirm DoUI calls BeginFrame(new Vector2Int(Screen.width, Screen.height)) each frame. Refer to Coordinate spaces and Handle resize.

Additional resources