Get started Build your first screen
Get started

Build your first screen

You’ll turn the starter’s message and button into a click counter. We’ll add state and an action in C#, display them in the UI, then make the same screen work in a browser without Unity.

Before you start

Open the project from Install and run Loom and make sure Play mode is stopped. We’ll edit Assets/Scripts/UIBridge.cs and the UI files in the UI/ folder beside Assets/.

Define a bridge

The screen needs a title and a count to display. We’ll store both on the bridge and add a Click() action that increases the count whenever the user presses the button.

Replace the contents of Assets/Scripts/UIBridge.cs with:

C#
using Loom;

[Bridge]
public partial class UIBridge : LoomBridgeBase
{
    public string Title { get; set; } = "Main Menu";
    public int Clicks { get; set; }

    [BridgeAction]
    public void Click()
    {
        Clicks += 1;
    }
}

Like Message in the starter, Title and Clicks become values the UI can read. The count starts at zero. When the UI calls Click(), the change to Clicks is sent back to the screen.

Save the file and wait for Unity to compile. Loom updates the declarations in UI/generated/ automatically. In TypeScript, the names start with a lowercase letter: title, clicks, and click.

Render the screen

Now let’s show those values. Replace the contents of UI/src/App.tsx with:

TSX
import { useBridge } from '@loomgui/bridge';

export default function MainMenu() {
  const bridge = useBridge();

  return (
    <main class="loom-app">
      <h1>{bridge.title}</h1>
      <button onClick={() => void bridge.click()}>
        Clicked {bridge.clicks} times
      </button>
    </main>
  );
}

useBridge() gives the component access to the bridge provided by the starter in UI/src/index.tsx. The expressions in braces read its current values, and Solid updates the heading and button text when those values change. Keep the reads as bridge.title and bridge.clicks inside the JSX so Solid can track them.

Clicking the button calls bridge.click(). That action runs Click() in C#; the resulting change to Clicks then updates the button text.

Update the browser mocks

The screen now expects title, clicks, and click, so we need to replace the starter’s message and ping configuration too. Open UI/src/bridge.ts and replace its contents with:

ts
import { bootBridge } from '@loomgui/bridge';

export const bridge = bootBridge({
  initial: { title: 'Main Menu', clicks: 0 },
  mockActions: ({ state }) => ({
    click: () => { state.clicks += 1; },
  }),
});

The initial values give the UI something to display at startup. Once it connects to Unity, the game supplies the values. When you preview the UI on its own, it starts with these values and uses the mock click action to increase the count instead.

Keep UI/src/index.tsx as it is. It already passes this bridge to BridgeProvider and renders the app inside it.

Verify the screen

From a terminal in UI/, run:

Shell
npm run typecheck

This checks that the UI and mocks use fields and actions from the generated bridge. If it reports message or ping, check that both UI files have been updated. If it doesn’t recognize title, clicks, or click, check the Unity Console for C# compilation errors.

Enter Play in the scene you configured during installation. You’ll see Main Menu and Clicked 0 times. Click the button twice: the count becomes 1, then 2. Unity is running the action and supplying the new count.

Now stop Play. In the terminal, start the browser preview:

Shell
npm run dev

Open the URL printed in the terminal. The count starts at 0 again, and the button increases it using the mock action. You’re using the same screen with a separate set of values, so these clicks don’t change the game.

Keep going

Continue with Development workflow to move between the Game view and browser while you work. Then Build a pause menu connects a larger UI to game time, gameplay input, and keyboard and gamepad navigation.

Loom documentation

Search docs

Esc

Type a word or phrase to search the documentation.

Type a word or phrase to search the documentation.