Building UI Screens and routing
Building UI

Screens and routing

Structure Solid screens and switch between them from bridge state.

Loom does not require a router. Most game UIs work best when C# owns the current game/UI mode and the Solid app renders the matching screen.

Screen state

Define a screen value on your bridge:

C#
public enum GameScreen
{
    Splash,
    MainMenu,
    Hud,
    Pause
}

[Bridge]
public partial class UIBridge : LoomBridgeBase
{
    public GameScreen CurrentScreen { get; set; } = GameScreen.Splash;
}

After regenerating types, the UI receives a string-literal union for the screen value.

Render from state

In App.tsx, switch on bridge state:

TSX
import { Match, Switch } from 'solid-js';
import { useBridge } from '@loomgui/bridge';
import { Splash } from './screens/Splash';
import { MainMenu } from './screens/MainMenu';
import { Hud } from './screens/Hud';
import { Pause } from './screens/Pause';

export function App() {
  const bridge = useBridge();

  return (
    <Switch>
      <Match when={bridge.currentScreen === 'Splash'}>
        <Splash />
      </Match>
      <Match when={bridge.currentScreen === 'MainMenu'}>
        <MainMenu />
      </Match>
      <Match when={bridge.currentScreen === 'Hud'}>
        <Hud />
      </Match>
      <Match when={bridge.currentScreen === 'Pause'}>
        <Pause />
      </Match>
    </Switch>
  );
}

Change screens from C#

Gameplay code can update the bridge directly:

C#
UIBridge.Instance.CurrentScreen = GameScreen.Hud;

For UI-triggered transitions, expose an action:

C#
[BridgeAction]
public void StartGame()
{
    LoomRuntime.KeyboardMode = LoomKeyboardMode.Gameplay;
    CurrentScreen = GameScreen.Hud;
}

For a keyboard-navigable menu, make the inverse transition in the same C# action that updates screen state and the game’s input action map:

C#
[BridgeAction]
public void OpenPauseMenu()
{
    gameInput.SwitchToUI();
    LoomRuntime.KeyboardMode = LoomKeyboardMode.Navigation;
    CurrentScreen = GameScreen.Pause;
}

Solid calls bridge.openPauseMenu() like any other action. Keep focus order in the DOM with semantic controls and tabindex, and conditionally render inactive screens. Unity remains the authority for whether global keyboard navigation is active.

Organize screens

A simple structure scales well:

UI/src/
  App.tsx
  screens/
    Splash.tsx
    MainMenu.tsx
    Hud.tsx
    Pause.tsx
  components/
    Button.tsx
    Panel.tsx

Keep screen-level layout in screens, reusable controls in components, and global tokens or resets in styles.css.

Loom documentation

Search docs

Esc

Type a word or phrase to search the documentation.

Type a word or phrase to search the documentation.