loomgui.com ↗

Screens and routing

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:

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:

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:

UIBridge.Instance.CurrentScreen = GameScreen.Hud;

For UI-triggered transitions, expose an action:

[BridgeAction]
public void StartGame()
{
    CurrentScreen = GameScreen.Hud;
}

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.