Your first screen
This walks you from a freshly installed Loom package to a working screen you can click. The flow is: scaffold the UI app, write a bridge in C#, add the Loom UI component to your scene, then build the screen.
Scaffold the UI project.
In the Editor, run
Loom -> Setup UI Project. It creates a Vite + Solid app at<ProjectRoot>/UI/from the bundled starter template and then runsLoom -> Sync UI Dependenciesfor you (installs the@loomgui/*packages and runsnpm install). You get:UI/ index.html package.json tsconfig.json vite.config.ts # outDir 'dist', base './' preconfigured for Loom src/index.tsx # boots the bridge, mounts <App/> src/App.tsx # starter "Loom is running" screen src/styles.css generated/bridge.d.ts # typed bridge surface (regenerated from your C#)It won’t overwrite a non-empty
UI/. If one already exists, it tells you and stops.Define your bridge in C#.
Create a bridge class anywhere under
Assets/(e.g.Assets/Scripts/UI/GameBridge.cs). The[Bridge]attribute marks it as the contract between C# and your UI. The class must inheritLoomBridgeBase; the source generator requires it:// Assets/Scripts/UI/GameBridge.cs using Loom; [Bridge] public partial class GameBridge : LoomBridgeBase { [BridgeState] public int Score { get; set; } [BridgeAction] public void AddPoint() { Score += 1; } }It must be
partialso the source generator can add plumbing to it. Every time Unity recompiles, the matching TypeScript types are emitted automatically toUI/generated/bridge.d.ts(open it any time withLoom -> Open Generated bridge.d.ts).Add a Loom UI component to your startup scene.
Open your startup scene and run
Loom -> Setup UI in Current Scene. This adds a single Loom UI GameObject that handles the canvas, input capture, and runtime initialization for you. Re-running it is safe; it skips setup if aLoomUIcomponent is already present.Alternatively, add the
LoomUIcomponent manually to any existing GameObject in the scene. That’s the only scene setup step; you don’t need a separate bootstrap MonoBehaviour.Hit Play.
LoomUIbuilds the Loom Canvas and starts the runtime on Awake. Access your bridge from gameplay code via the generated static property:GameBridge.Instance.Score = 10;Build your screen.
The scaffold’s
UI/src/App.tsxrenders a placeholder. Replace it to read state and call actions through the bridge, the C# and TypeScript sides line up by name (Score→score,AddPoint→addPoint):
[BridgeState]
public int Score { get; set; }
[BridgeAction]
public void AddPoint() {
Score += 1;
}// UI/src/App.tsx
import { useBridge } from "@loomgui/bridge";
export default function App() {
const bridge = useBridge();
return (
<div class="app">
<span>{bridge.state.score}</span>
<button onClick={() => bridge.actions.addPoint()}>+1</button>
</div>
);
}Seed the matching initial state in UI/src/index.tsx’s bootBridge({ initial: { score: 0 } }) call, it’s the snapshot the UI renders before the engine’s
first push, and the seed for Mock mode.
Click +1 in Play mode: bridge.actions.addPoint() reaches C#, Score bumps, and the UI re-renders with the new value.
Where to go next
- The bridge: full reference for state, actions, and events.
- Mock mode: author the UI without Unity running.
- Player builds: how your UI is bundled when you ship.
unity/sample/UI/src/screens/Counter.tsx: the same bridge pattern in the in-repo sample.