FlowAsset
A Flow is a named collection of screens. Each screen has its own widget layout. The host transitions players between screens at runtime — show one player a pick_word screen while the others wait on lobby, advance everyone to a round screen when the game starts, and so on.
Flows are the right abstraction whenever the phone-side UI changes during a session. For single-screen sessions, Templates are simpler.
Authoring
- Create the asset.
Assets → Create → PairKit → Flow Asset. - Author screens in the inline editor — give each a name, drop in widgets via the
WidgetDefinitionsfactories, set one screen as theinitialScreen. - Drag the FlowAsset into the
Flow Assetslot onPhoneControllerManager. If bothTemplateandFlow Assetare set, the flow wins.
The custom inspector runs FlowValidator on save — missing initialScreen, duplicate widget ids, empty screens, and similar authoring mistakes surface inline before you press play.
Runtime API
The host moves players between screens with these methods on PhoneControllerManager:
// Move every player to the same screen, with optional initial data.manager.ShowScreenToAll("lobby", new { count = 0 });
// Move a specific player to a screen.manager.ShowScreen(player.Id, "spectate");
// Move several players in one call.manager.ShowScreen(new[] { p1.Id, p2.Id }, "round");
// Shallow-merge new data into the player's current screen state.manager.UpdateScreenDataForAll("lobby", new { count = newCount });manager.UpdateScreenData(player.Id, "round", new { hp = 80 });Scoped input
OnInput fires for every event from every screen — useful, but verbose. With a flow you can subscribe per (screen, widget):
var unsub = manager.OnWidgetInput("lobby", "name_input", (player, evt) =>{ var name = evt.GetString("text"); manager.UpdateScreenDataForAll("lobby", new { count = ++_ready }); if (_ready == manager.Players.Count) manager.ShowScreenToAll("round");});
// Later, when leaving the lobby:unsub();The returned delegate is your unsubscribe — call it when leaving the screen so handlers don’t leak across rounds.
Stale input
Input from a screen the player is no longer on is dropped automatically by the relay (counted as pairkit_stale_input_total — see protocol/metrics). You don’t need to defensively check the screen name in your handler.
Pitfalls
- Forgetting to call the unsubscribe delegate from
OnWidgetInput. Subscriptions accumulate. Symptom: input fires the same handler N times after N rounds. - Using
ShowScreenwhile players are mid-input. The screen change cancels anyPromptAsyncfor that player withOperationCanceledException. Either await the prompt first, or design the flow so transitions happen between prompts. - Author-time
Templateslot still set. The flow takes precedence at runtime, but a leftoverTemplatein the inspector confuses readers of the scene. Clear it.
Next
- One-player request/response on top of a flow:
PromptAsync. - One-off overlays without a full flow:
RequestAsync.