loomgui.com ↗

State and collections

State is any public property on your bridge that the UI should render.

public int Coins { get; set; }
public string CurrentScreen { get; set; } = "MainMenu";

Assigning a state property pushes the new value to the UI.

Nested state

Use classes for grouped state that should update per field:

public sealed class PlayerState
{
    public string Name { get; set; } = "";
    public int Health { get; set; }
}

public PlayerState Player { get; set; } = new();

Initialize nested state before Loom starts. A nested state object that is null during registration cannot be walked until you assign the parent again.

Snapshot collections

Arrays, List<T>, and Dictionary<K,V> use snapshot semantics. Reassign the whole collection to push a new value:

Items = new List<ItemState>(Items) { newItem };

In-place mutation does not call the property setter:

Items.Add(newItem); // Does not sync by itself.

Use snapshots for small lists or values that naturally update as a whole.

Reactive collections

Use ReactiveList<T> or ReactiveMap<K,V> when the UI needs granular changes:

public ReactiveList<QuestState> Quests { get; } = new();

Reactive collections are better for lists or maps that change frequently while preserving item identity.

UI usage

The generated TypeScript state uses camelCase names:

const bridge = useBridge();

bridge.currentScreen;
bridge.player.health;
bridge.quests;

Run Loom -> Regenerate Types after changing the C# state shape.