iOS dashboards · no Swift required

Programmable iOS dashboards,
made effortless.

CAR-TER lets makers and developers connect any service to a sleek, fully customizable iOS dashboard & remote — described in JSON and driven live over a WebSocket mesh. No Swift, no app to ship.

Read the guide →Control reference
Where to go next
Pick a path
🧮

Architecture

The three actors — app, relay, your server — and how a JSON layout becomes a live UI.

🔌

Connection & Pairing

Channels, roles, QR pairing, and the hosted Connect+ gateway vs. self-hosted relay.

🧱

Control Catalog

Every control type — inputs, displays, containers — and whether it sends, receives, or both.

🐍

Python Server

Stand up a backend in ~30 lines with the MeshSocket client and start streaming telemetry.

📐

Layout Schema

The full JSON shape: tabs, grids, controls, sync, actions, and theming.

Live Editing

Drive the app from an editor or LLM and watch layouts update on-device in real time.

Build for CAR-TER

CAR-TER turns an iPhone or iPad into any remote or dashboard you can describe in JSON. A layout is a JSON document — tabs, a grid, and controls — that the app renders as a swift UI. Those controls talk to your server over a persistent WebSocket mesh called MeshSocket.

Your job, as an integrator, is to write the program on the other end of that socket: the thing that feeds the displays and handles the inputs.

The mental model (five minutes)

There are three actors. See Architecture for the full picture.

flowchart LR app["CAR-TER app<br/>(phone / iPad)<br/>renders JSON layout"] relay["MeshSocket relay<br/>routes by channel"] server["Your server<br/>(any language)<br/>data + logic"] app -->|"identify · actions"| relay relay -->|"broadcast"| app server -->|"identify · broadcast · routed RPC"| relay relay -->|"broadcast · routed RPC"| server
  1. The app loads a layout and connects to a relay, joining a channel with a role.
  2. The relay is a small message router. It fans out broadcasts to everyone on a channel and routes point-to-point requests between members. You can run the open-source relay yourself, or use the hosted Connect+ gateway — see Connection & Pairing.
  3. Your server joins the same channel and does the real work: it broadcasts data the controls listen for, and receives the actions controls emit.

Two data directions, both covered in Data Flow — sync & actions:

What you'll build

A minimal integration is ~30 lines: connect, identify, and either broadcast a number on a timer or print the actions that arrive. From there you compose: telemetry dashboards, interactive controllers, chat, force-directed graphs, and dynamically-generated tabs.

A complete tiny example

A layout with one gauge that listens, and one button that sends:

{
  "name": "Hello CAR-TER",
  "version": 1,
  "connection": {
    "url": "ws://192.168.1.50:8765",
    "identity": { "name": "Dashboard", "channel": "demo", "role": "viewer" }
  },
  "tabs": [{
    "title": "Main", "icon": "gauge.with.dots.needle.67percent",
    "grid": { "columns": 2, "rows": 2 },
    "children": [
      { "type": "gauge", "id": "cpu", "position": [0,0], "label": "CPU",
        "min": 0, "max": 100,
        "sync": [{ "method": "meshsocket", "type": "listen",
                   "event": "broadcast", "filter": { "msg_type": "metrics" },
                   "valuePath": "cpu" }] },
      { "type": "button", "id": "refresh", "position": [0,1], "label": "Refresh",
        "action": { "method": "meshsocket", "mode": "broadcast",
                    "event": "broadcast_request",
                    "payload": { "msg_type": "command", "command": "refresh" } } }
    ]
  }]
}

Your server, on the demo channel, broadcasts { "msg_type": "metrics", "cpu": 73 } to move the gauge, and listens for { "msg_type": "command", "command": "refresh" } when the button is tapped. The exact frames are spelled out in The MeshSocket Protocol and Data Flow — sync & actions; full schema in Layout Schema.

Next: Architecture.