---
title: "ui.surface@1 · OpenVibe.Services"
canonical: "https://openvibe.services/docs/contracts/ui.surface"
updated: null
---

# ui.surface@1 · OpenVibe.Services

HTML: [ui.surface@1 · OpenVibe.Services](https://openvibe.services/docs/contracts/ui.surface)

# UiSurface `ui.surface@1`

Generated at 2026-11-13 06:25:48 UTC from [`openvibe-contracts v0.419.0`](https://github.com/OpenVibers/OpenVibe.Contracts/tree/v0.419.0) and [`openvibe-sdk v0.161.0`](https://github.com/OpenVibers/OpenVibe.SDK/tree/v0.161.0).

- Version: 1.0.0
- Owner: contracts
- Visibility: public
- Status: active
- Compatibility: backward
- Schema: [`https://openvibe.network/contracts/ui/surface.v1.json`](/docs/contracts/ui.surface.json)

ui.surface@1: the catalog a product publishes for one surface people may arrange (bot.controls, bot.overlay, live.channel, dock, chat.composer, navbar.shortcuts). It names the surface, its device classes and grid, the theme tokens its styles draw from, and every part a layout may place. A part says what it is (stick, button, slider, readout, video, list), whether it is required or pressed, its minimum cells and the minimum pixels the product guarantees (44 px for anything pressed, larger for Stop), the sizes and styles it allows, the bindings it accepts, and the parts it must never cover. A layout is validated against this catalog (openvibe-sdk/ui-layout); a layout can arrange only what the catalog has and can never add a power. The catalog is data: a layout or an AI answer never carries code or a URL.

## Fields

| Field | Type | Required | Description | Constraints |
| --- | --- | --- | --- | --- |
| `id` | string | yes | The surface id: <product>.<surface>, e.g. bot.controls. | - `pattern ^[a-z][a-z0-9_]*(\.[a-z0-9_]+)+$`<br>- `maxLength 80` |
| `version` | integer | yes | The catalog version. A layout names the version it was made against. | - `minimum 1` |
| `name` | string | yes | What the surface is called where a person sees it. | - `minLength 1`<br>- `maxLength 80` |
| `description` | string |  |  | - `maxLength 500` |
| `devices` | array of enum | yes | The device classes this surface offers. | - `minItems 1`<br>- `maxItems 3`<br>- `unique items`<br>- `items: one of "phone", "tablet", "computer"` |
| `grid` | object | yes |  | - `no other fields` |
| `grid.columns` | object | yes | The grid's columns per device class: 4 on a phone and 12 on a computer in the design; a product may choose otherwise within these bounds. | - `no other fields` |
| `grid.columns.phone` | integer | yes |  | - `minimum 2`<br>- `maximum 8` |
| `grid.columns.tablet` | integer | yes |  | - `minimum 2`<br>- `maximum 16` |
| `grid.columns.computer` | integer | yes |  | - `minimum 2`<br>- `maximum 24` |
| `grid.cell_px` | object | yes | The smallest a cell is rendered at that device class, in CSS pixels, at the narrowest supported width. The validator multiplies a part's cells by this to check the 44 px rule. | - `no other fields` |
| `grid.cell_px.phone` | integer | yes |  | - `minimum 24`<br>- `maximum 200` |
| `grid.cell_px.tablet` | integer | yes |  | - `minimum 24`<br>- `maximum 200` |
| `grid.cell_px.computer` | integer | yes |  | - `minimum 24`<br>- `maximum 200` |
| `theme_tokens` | array of string | yes | The theme tokens a tint may name (accent, surface, danger, ...). Never a colour value: the theme decides what the token is. | - `minItems 1`<br>- `maxItems 64`<br>- `unique items`<br>- `items: pattern ^[a-z][a-z0-9-]{0,39}$` |
| `parts` | `https://openvibe.network/contracts/ui/surface.v1.json#/$defs/part` | yes |  | - `minItems 1`<br>- `maxItems 64` |

## Examples

From the contract's own test fixtures: valid ones validate, rejected ones must fail.

 Valid: bot-controls

~~~~
{
  "id": "bot.controls",
  "version": 1,
  "name": "Robot controls",
  "description": "The robot's own panel: an optional plain Stop, the stick, the head slider and the readouts.",
  "devices": [
    "phone",
    "tablet",
    "computer"
  ],
  "grid": {
    "columns": {
      "phone": 4,
      "tablet": 8,
      "computer": 12
    },
    "cell_px": {
      "phone": 44,
      "tablet": 44,
      "computer": 44
    }
  },
  "theme_tokens": [
    "accent",
    "surface",
    "surface-raised",
    "text",
    "muted",
    "danger",
    "warning",
    "success"
  ],
  "parts": [
    {
      "id": "stop",
      "name": "Stop",
      "kind": "button",
      "required": false,
      "pressed": true,
      "min": {
        "w": 1,
        "h": 1,
        "px": 44
      },
      "sizes": [
        {
          "w": 1,
          "h": 1
        },
        {
          "w": 2,
          "h": 2
        }
      ],
      "styles": {
        "tints": [
          "surface"
        ],
        "shapes": [
          "pill",
          "square"
        ],
        "opacity": {
          "min": 0.4,
          "max": 1
        },
        "label": true
      },
      "bindings": {
        "keys": [
          "Space"
        ],
        "gamepad": [
          "south"
        ]
      },
      "never_covers": []
    },
    {
      "id": "stick",
      "name": "Drive stick",
      "kind": "stick",
      "required": false,
      "pressed": true,
      "min": {
        "w": 3,
        "h": 3
      },
      "sizes": [
        {
          "w": 3,
          "h": 3
        },
        {
          "w": 4,
          "h": 4
        }
      ],
      "styles": {
        "tints": [
          "surface",
          "surface-raised"
        ],
        "shapes": [
          "round"
        ],
        "opacity": {
          "min": 0.6,
          "max": 1
        },
        "label": false
      },
      "bindings": {
        "keys": [
          "W",
          "A",
          "S",
          "D"
        ],
        "gamepad": [
          "left-stick"
        ]
      },
      "never_covers": [
        "stop"
      ]
    },
    {
      "id": "head",
      "name": "Head",
      "kind": "slider",
      "required": false,
      "pressed": true,
      "min": {
        "w": 2,
        "h": 2
      },
      "styles": {
        "tints": [
          "accent",
          "surface-raised"
        ],
        "shapes": [
          "pill",
          "square"
        ],
        "opacity": {
          "min": 0.4,
          "max": 1
        },
        "label": true
      },
      "bindings": {
        "keys": [
          "ArrowUp",
          "ArrowDown"
        ],
        "gamepad": [
          "right-stick-y"
        ]
      },
      "never_covers": [
        "stop"
      ]
    },
    {
      "id": "battery",
      "name": "Battery",
      "kind": "readout",
      "required": false,
      "pressed": false,
      "min": {
        "w": 1,
        "h": 1
      },
      "styles": {
        "tints": [
          "text",
          "muted",
          "success"
        ],
        "shapes": [
          "pill",
          "square"
        ],
        "opacity": {
          "min": 0.4,
          "max": 1
        },
        "label": true
      },
      "bindings": {
        "keys": [],
        "gamepad": []
      },
      "never_covers": [
        "stop"
      ]
    },
    {
      "id": "latency",
      "name": "Latency",
      "kind": "readout",
      "required": false,
      "pressed": false,
      "min": {
        "w": 1,
        "h": 1
      },
      "styles": {
        "tints": [
          "text",
          "muted"
        ],
        "shapes": [
          "pill",
          "square"
        ],
        "opacity": {
          "min": 0.4,
          "max": 1
        },
        "label": true
      },
      "bindings": {
        "keys": [],
        "gamepad": []
      },
      "never_covers": [
        "stop"
      ]
    }
  ]
}
~~~~

Valid: looi-controls

~~~~
{
  "id": "bot.controls",
  "version": 1,
  "name": "Robot controls",
  "description": "LOOI's panel from its manifest (LOOI 1.0.0): each part says what it sends or shows, for the AI that arranges it.",
  "devices": [
    "phone",
    "tablet",
    "computer"
  ],
  "grid": {
    "columns": {
      "phone": 4,
      "tablet": 8,
      "computer": 12
    },
    "cell_px": {
      "phone": 44,
      "tablet": 44,
      "computer": 44
    }
  },
  "theme_tokens": [
    "accent",
    "surface",
    "surface-raised",
    "text",
    "muted",
    "danger",
    "warning",
    "success"
  ],
  "parts": [
    {
      "id": "stick",
      "name": "Drive stick",
      "kind": "stick",
      "required": false,
      "pressed": true,
      "min": {
        "w": 2,
        "h": 2
      },
      "styles": {
        "tints": [
          "surface",
          "accent"
        ],
        "shapes": [
          "round",
          "pill",
          "square"
        ],
        "opacity": {
          "min": 0.4,
          "max": 1
        },
        "label": true
      },
      "bindings": {
        "keys": [
          "ArrowUp",
          "ArrowDown",
          "ArrowLeft",
          "ArrowRight"
        ],
        "gamepad": [
          "left-stick"
        ]
      },
      "never_covers": [
        "stop"
      ],
      "command": {
        "kind": "drive",
        "class": "motion",
        "label": "Drive",
        "value": {
          "throttle": [
            -1,
            1
          ],
          "steer": [
            -1,
            1
          ]
        },
        "lifetime_ms": 500,
        "delivery_ms": {
          "min": 1,
          "max": 300
        },
        "release": "stop",
        "control": "stick"
      }
    },
    {
      "id": "head",
      "name": "Head",
      "kind": "slider",
      "required": false,
      "pressed": true,
      "min": {
        "w": 2,
        "h": 1
      },
      "styles": {
        "tints": [
          "accent",
          "surface"
        ],
        "shapes": [
          "round",
          "pill",
          "square"
        ],
        "opacity": {
          "min": 0.4,
          "max": 1
        },
        "label": true
      },
      "bindings": {
        "keys": [
          "q",
          "e"
        ],
        "gamepad": []
      },
      "never_covers": [
        "stop"
      ],
      "command": {
        "kind": "actuator",
        "name": "head",
        "class": "motion",
        "label": "Head",
        "value": {
          "head": [
            -1,
            1
          ]
        },
        "lifetime_ms": 500,
        "delivery_ms": {
          "min": 1,
          "max": 300
        },
        "release": "hold",
        "control": "slider"
      }
    },
    {
      "id": "headlight",
      "name": "Headlights",
      "kind": "button",
      "required": false,
      "pressed": true,
      "min": {
        "w": 2,
        "h": 1
      },
      "styles": {
        "tints": [
          "surface",
          "accent"
        ],
        "shapes": [
          "round",
          "pill",
          "square"
        ],
        "opacity": {
          "min": 0.4,
          "max": 1
        },
        "label": true
      },
      "bindings": {
        "keys": [
          "l"
        ],
        "gamepad": []
      },
      "never_covers": [
        "stop"
      ],
      "command": {
        "kind": "headlight",
        "class": "state",
        "label": "Headlights",
        "value": {
          "on": "boolean"
        },
        "delivery_ms": {
          "min": 1,
          "max": 250
        },
        "min_left_ms": 50,
        "rate_per_s": 2,
        "release": "none",
        "latched": true,
        "confirm": "p7_headlight",
        "control": "toggle"
      }
    },
    {
      "id": "battery",
      "name": "Battery",
      "kind": "readout",
      "required": false,
      "pressed": false,
      "min": {
        "w": 1,
        "h": 1
      },
      "styles": {
        "tints": [
          "text",
          "surface"
        ],
        "shapes": [
          "round",
          "pill",
          "square"
        ],
        "opacity": {
          "min": 0.4,
          "max": 1
        },
        "label": true
      },
      "bindings": {
        "keys": [],
        "gamepad": []
      },
      "reads": {
        "key": "battery",
        "label": "Battery",
        "unit": "%",
        "range": [
          0,
          100
        ],
        "source": "poll",
        "control": "meter"
      }
    },
    {
      "id": "commander",
      "name": "Who is driving",
      "kind": "readout",
      "required": false,
      "pressed": false,
      "min": {
        "w": 2,
        "h": 1
      },
      "styles": {
        "tints": [
          "text",
          "surface"
        ],
        "shapes": [
          "round",
          "pill",
          "square"
        ],
        "opacity": {
          "min": 0.4,
          "max": 1
        },
        "label": true
      },
      "bindings": {
        "keys": [],
        "gamepad": []
      },
      "reads": {
        "key": "p7_commander",
        "label": "Who is driving",
        "fields": {
          "subject": "string",
          "role": [
            "owner",
            "mod",
            "operator"
          ],
          "channel": [
            "drive",
            "head",
            "headlight"
          ],
          "at": "ms"
        },
        "source": "push",
        "control": "badge"
      }
    },
    {
      "id": "stop",
      "name": "Stop",
      "kind": "button",
      "required": false,
      "pressed": true,
      "min": {
        "w": 1,
        "h": 1,
        "px": 44
      },
      "styles": {
        "tints": [
          "surface"
        ],
        "shapes": [
          "pill",
          "square"
        ],
        "opacity": {
          "min": 0.4,
          "max": 1
        },
        "label": true
      },
      "bindings": {
        "keys": [
          "Space"
        ],
        "gamepad": [
          "south"
        ]
      }
    }
  ]
}
~~~~

Rejected: colour-tint

~~~~
{
  "id": "bot.controls",
  "version": 1,
  "name": "Robot controls",
  "devices": [
    "phone"
  ],
  "grid": {
    "columns": {
      "phone": 4,
      "tablet": 8,
      "computer": 12
    },
    "cell_px": {
      "phone": 44,
      "tablet": 44,
      "computer": 44
    }
  },
  "theme_tokens": [
    "danger"
  ],
  "parts": [
    {
      "id": "stop",
      "name": "Stop",
      "kind": "button",
      "required": true,
      "pressed": true,
      "min": {
        "w": 2,
        "h": 2
      },
      "styles": {
        "tints": [
          "#ff0000"
        ],
        "shapes": [
          "round"
        ]
      },
      "bindings": {
        "keys": [
          "Space"
        ],
        "gamepad": [
          "south"
        ]
      }
    }
  ]
}
~~~~

Rejected: command-motion-without-release

~~~~
{
  "id": "bot.controls",
  "version": 1,
  "name": "Robot controls",
  "description": "LOOI's panel from its manifest (LOOI 1.0.0): each part says what it sends or shows, for the AI that arranges it.",
  "devices": [
    "phone",
    "tablet",
    "computer"
  ],
  "grid": {
    "columns": {
      "phone": 4,
      "tablet": 8,
      "computer": 12
    },
    "cell_px": {
      "phone": 44,
      "tablet": 44,
      "computer": 44
    }
  },
  "theme_tokens": [
    "accent",
    "surface",
    "surface-raised",
    "text",
    "muted",
    "danger",
    "warning",
    "success"
  ],
  "parts": [
    {
      "id": "stick",
      "name": "Drive stick",
      "kind": "stick",
      "required": false,
      "pressed": true,
      "min": {
        "w": 2,
        "h": 2
      },
      "styles": {
        "tints": [
          "surface",
          "accent"
        ],
        "shapes": [
          "round",
          "pill",
          "square"
        ],
        "opacity": {
          "min": 0.4,
          "max": 1
        },
        "label": true
      },
      "bindings": {
        "keys": [
          "ArrowUp",
          "ArrowDown",
          "ArrowLeft",
          "ArrowRight"
        ],
        "gamepad": [
          "left-stick"
        ]
      },
      "never_covers": [
        "stop"
      ],
      "command": {
        "kind": "drive",
        "class": "motion",
        "label": "Drive",
        "value": {
          "throttle": [
            -1,
            1
          ],
          "steer": [
            -1,
            1
          ]
        },
        "lifetime_ms": 500,
        "delivery_ms": {
          "min": 1,
          "max": 300
        },
        "control": "stick"
      }
    },
    {
      "id": "head",
      "name": "Head",
      "kind": "slider",
      "required": false,
      "pressed": true,
      "min": {
        "w": 2,
        "h": 1
      },
      "styles": {
        "tints": [
          "accent",
          "surface"
        ],
        "shapes": [
          "round",
          "pill",
          "square"
        ],
        "opacity": {
          "min": 0.4,
          "max": 1
        },
        "label": true
      },
      "bindings": {
        "keys": [
          "q",
          "e"
        ],
        "gamepad": []
      },
      "never_covers": [
        "stop"
      ],
      "command": {
        "kind": "actuator",
        "name": "head",
        "class": "motion",
        "label": "Head",
        "value": {
          "head": [
            -1,
            1
          ]
        },
        "lifetime_ms": 500,
        "delivery_ms": {
          "min": 1,
          "max": 300
        },
        "release": "hold",
        "control": "slider"
      }
    },
    {
      "id": "headlight",
      "name": "Headlights",
      "kind": "button",
      "required": false,
      "pressed": true,
      "min": {
        "w": 2,
        "h": 1
      },
      "styles": {
        "tints": [
          "surface",
          "accent"
        ],
        "shapes": [
          "round",
          "pill",
          "square"
        ],
        "opacity": {
          "min": 0.4,
          "max": 1
        },
        "label": true
      },
      "bindings": {
        "keys": [
          "l"
        ],
        "gamepad": []
      },
      "never_covers": [
        "stop"
      ],
      "command": {
        "kind": "headlight",
        "class": "state",
        "label": "Headlights",
        "value": {
          "on": "boolean"
        },
        "delivery_ms": {
          "min": 1,
          "max": 250
        },
        "min_left_ms": 50,
        "rate_per_s": 2,
        "release": "none",
        "latched": true,
        "confirm": "p7_headlight",
        "control": "toggle"
      }
    },
    {
      "id": "battery",
      "name": "Battery",
      "kind": "readout",
      "required": false,
      "pressed": false,
      "min": {
        "w": 1,
        "h": 1
      },
      "styles": {
        "tints": [
          "text",
          "surface"
        ],
        "shapes": [
          "round",
          "pill",
          "square"
        ],
        "opacity": {
          "min": 0.4,
          "max": 1
        },
        "label": true
      },
      "bindings": {
        "keys": [],
        "gamepad": []
      },
      "reads": {
        "key": "battery",
        "label": "Battery",
        "unit": "%",
        "range": [
          0,
          100
        ],
        "source": "poll",
        "control": "meter"
      }
    },
    {
      "id": "commander",
      "name": "Who is driving",
      "kind": "readout",
      "required": false,
      "pressed": false,
      "min": {
        "w": 2,
        "h": 1
      },
      "styles": {
        "tints": [
          "text",
          "surface"
        ],
        "shapes": [
          "round",
          "pill",
          "square"
        ],
        "opacity": {
          "min": 0.4,
          "max": 1
        },
        "label": true
      },
      "bindings": {
        "keys": [],
        "gamepad": []
      },
      "reads": {
        "key": "p7_commander",
        "label": "Who is driving",
        "fields": {
          "subject": "string",
          "role": [
            "owner",
            "mod",
            "operator"
          ],
          "channel": [
            "drive",
            "head",
            "headlight"
          ],
          "at": "ms"
        },
        "source": "push",
        "control": "badge"
      }
    },
    {
      "id": "stop",
      "name": "Stop",
      "kind": "button",
      "required": false,
      "pressed": true,
      "min": {
        "w": 1,
        "h": 1,
        "px": 44
      },
      "styles": {
        "tints": [
          "surface"
        ],
        "shapes": [
          "pill",
          "square"
        ],
        "opacity": {
          "min": 0.4,
          "max": 1
        },
        "label": true
      },
      "bindings": {
        "keys": [
          "Space"
        ],
        "gamepad": [
          "south"
        ]
      }
    }
  ]
}
~~~~

Rejected: unknown-kind

~~~~
{
  "id": "bot.controls",
  "version": 1,
  "name": "Robot controls",
  "devices": [
    "phone"
  ],
  "grid": {
    "columns": {
      "phone": 4,
      "tablet": 8,
      "computer": 12
    },
    "cell_px": {
      "phone": 44,
      "tablet": 44,
      "computer": 44
    }
  },
  "theme_tokens": [
    "accent"
  ],
  "parts": [
    {
      "id": "stop",
      "name": "Stop",
      "kind": "power",
      "required": true,
      "pressed": true,
      "min": {
        "w": 2,
        "h": 2
      },
      "styles": {
        "tints": [
          "danger"
        ],
        "shapes": [
          "round"
        ]
      },
      "bindings": {
        "keys": [
          "Space"
        ],
        "gamepad": [
          "south"
        ]
      }
    }
  ]
}
~~~~

## Validate

~~~~
const contracts = require('openvibe-contracts');
contracts.validate('ui.surface@1', value);   // { valid, errors: [{ path, message }] }
~~~~
