Layout Schema

Field reference for the layout JSON. Concepts are in Layouts; this is the lookup. (The app is the source of truth; treat unspecified fields as optional with sane defaults.)

LayoutConfig (top level)

{
  "name": "string (required) — display name",
  "headerTitle": "string — header bar title (defaults to name)",
  "version": 1,
  "accentColor": "#hex — app accent color (default #667eea)",
  "connection": { ConnectionConfig } | null,
  "appearance": { AppearanceConfig } | null,
  "theme": { ThemeConfig } | null,
  "tabs": [ TabDefinition, … ],
  "pollGroups": { "name": { "event": "string", "interval": number, "payload": any } },
  "dynamicTabs": [ { "event": "string" } ]
}

version is required by editor/push tooling — include "version": 1. theme and per-control theming are premium (custom theming requires the Pro entitlement; otherwise the default glass theme is used). See Control Catalog.

ConnectionConfig

{
  "url": "wss://… or ws://… (required)",
  "token": "string | null",
  "e2eeKey": "base64 string | null",
  "identity": {
    "name": "string — device display name",
    "channel": "string — mesh channel",
    "role": "string — mesh role",
    "canBroadcast": false,
    "canRoute": false
  }
}

See Connection & Pairing.

TabDefinition

{
  "title": "string (required)",
  "icon": "string — SF Symbol name (required)",
  "grid": { "columns": int, "rows": int },
  "children": [ ChildDefinition, … ]
}

ChildDefinition — control or group

ControlDefinition

{
  "type": "button|toggle|slider|stepper|segmented|picker|datePicker|textInput|colorPicker|label|image|gauge|sparkline|progressRing|statusLight|map|graph|chat|qrCode|webView|logConsole|joystick|list|cardList|divider|spacer|…",
  "id": "string (required, unique)",
  "position": [row, col],
  "span": [rowSpan, colSpan],         // default [1,1]
  "label": "string",
  "defaultValue": any,
  "icon": "string — SF Symbol",
  "tint": "#hex",
  "hideLabel": bool,
  "hideBackground": bool,

  // type-specific (see control-catalog):
  "min": number, "max": number, "step": number,
  "minIcon": "string", "maxIcon": "string",
  "options": ["string", …],
  "placeholder": "string",
  "text": "string (label type)",
  "systemName": "string (image type — SF Symbol)",
  "gaugeStyle": "full|three_quarter|half",
  "segments": [{ "limit": number, "color": "#hex" }],
  "progressStyle": "ring|bar",
  "sparklinePoints": int, "sparklineFill": bool,
  "pickerStyle": "menu|wheel|inline",
  "datePickerStyle": "compact|wheel|graphical",
  "datePickerMode": "date|time|dateAndTime",
  "mapStyle": "standard|satellite|hybrid", "mapInteractive": bool,
  "graphConfig": { … see the in-app graph doc },
  "config": { "target": string|null, "showTypingIndicators": bool, "historyCount": int }, // chat

  // behavior (see data-flow):
  "action": ActionDefinition,
  "sync": [ SyncDefinition, … ],
  "visible": { "when": "control-id", "operator": "eq|neq|gt|lt|gte|lte", "value": any },
  "haptic": "light|medium|heavy|success|warning|error|selection",
  "animation": "snappy|smooth|bouncy|gentle|instant",
  "longPressGroup": GroupDefinition,
  "longPressAction": ActionDefinition
}

GroupDefinition

{
  "type": "group",
  "id": "string (required)",
  "label": "string",
  "position": [row, col],
  "span": [rowSpan, colSpan],
  "grid": { "columns": int, "rows": int },
  "children": [ ChildDefinition, … ],
  "dynamic": "string — event name for dynamic content",
  "visible": { … }
}

ActionDefinition (device → server)

{
  "method": "meshsocket",
  "mode": "request | broadcast",
  "event": "broadcast_request | route_msg | route_msg_noreply",
  "payload": { "key": "{{value}}" }
}

mode: "request" awaits a reply; otherwise fire-and-forget. {{value}} is substituted with the control's value (native type when the whole string is exactly "{{value}}"). See Data Flow — sync & actions.

SyncDefinition (server → device)

{
  "method": "meshsocket",
  "type": "listen",
  "event": "broadcast | <custom>",
  "filter": { "key": "value" },
  "valuePath": "dot.notation.path"
}

event: "broadcast" listens on the shared channel; filter selects frames (shallow equality on each key); valuePath extracts the value. See Data Flow — sync & actions.

Grid positioning

  • position: [row, col] — zero-indexed within the parent grid.
  • span: [rowSpan, colSpan] — cells occupied (default [1, 1]).
  • Children must fit their parent grid (tab or group).

Icons

SF Symbol names, e.g. slider.horizontal.3, bolt.fill, gauge.with.dots.needle.67percent, map.fill, chart.line.uptrend.xyaxis, house.fill, antenna.radiowaves.left.and.right.

See also Control Catalog and Message Reference.