Skip to content

Widgets (wire format)

A widget is a flat JSON object. Its type field selects the schema; remaining fields vary per type. The TypeScript union in widgets.ts is the source of truth.

Per-widget reference pages list every field, every event, and a usage example. This page is the index.

Input widgets

Emit input.widget_event messages.

TypeCategory
joystickinput
buttoninput
dpadinput
text_inputinput
tap_areainput
choice_listinput
gridinput
drawing_canvasinput

Display widgets

Render-only. Never emit input.

TypeCategory
labeldisplay
imagedisplay
timerdisplay
progress_bardisplay

Why widgets are flat

Positions and sizes are flattened on the wire (position_x, position_y, size_w, size_h) so generated C# can stay as POD with nullable fields, no nested types. Any host that speaks JSON can emit them without a schema.

Data binding

String fields on display widgets may contain template placeholders like "{score}". The web controller resolves these against screen.data on mount and on every screen.update_data. Use {{ to embed a literal {.

Adding a new widget

  1. Add the interface to widgets.ts and a new entry in WIDGET_TYPES.
  2. Add it to the Widget union.
  3. Add a renderer in packages/web-controller/src/widgets/.
  4. Run pnpm --filter @pairkit/shared-protocol generate:csharp.
  5. Write the per-widget reference page under apps/web/src/content/docs/docs/widgets/.
  6. Add the new entry to WIDGET_CATEGORIES in scripts/generate-docs.ts and re-run the docs generator.