UiLayout ui.layout@1

Generated at from openvibe-contracts v0.419.0 and openvibe-sdk v0.161.0.

Version
1.0.0
Owner
contracts
Visibility
public
Status
active
Compatibility
backward
Schema
https://openvibe.network/contracts/ui/layout.v1.json

ui.layout@1: one person's arrangement of one surface on one device class. A layout names the surface and its catalog version, the device, its own name, its author and its sharing (private, link or gallery), and one entry per part it places. A part is visible or not, sits on the surface's grid (x, y, w, h in cells) or docks to an edge for an overlay, and carries a style (a theme token tint, a shape, opacity 0.4-1 and the label) and bindings. It is data only: no URL, no markup and no code may appear anywhere in it, and every part id, tint, shape, opacity, size and binding must be one the catalog allows. openvibe-sdk/ui-layout validates it before any server, editor or AI answer stores or shows it.

Fields

FieldTypeRequiredDescriptionConstraints
idstringAssigned by OpenVibe.Network when the layout is stored; absent in a draft, a share answer or an AI suggestion.
  • pattern ^lay_[0-9A-HJKMNP-TV-Z]{26}$
revisionintegerAssigned by the store; every change to a stored layout moves it by one.
  • minimum 1
activebooleanSet by OpenVibe.Network: the one layout a product draws for this surface on this device class. A draft, a share answer and an AI suggestion carry no active field.
surfacestringyes
  • pattern ^[a-z][a-z0-9_]*(\.[a-z0-9_]+)+$
  • maxLength 80
surface_versionintegeryes
  • minimum 1
deviceenumyes
  • one of "phone", "tablet", "computer"
namestringyesThe person's name for this layout; "My phone controls" is fine.
  • minLength 1
  • maxLength 80
authorobjectyesThe author's display name and, for a private or link layout, the subject. A share or gallery answer carries the display name only, never the account.
  • no other fields
author.namestringyes
  • minLength 1
  • maxLength 80
author.subjectidentity.subject-ref
sharingenumyes
  • one of "private", "link", "gallery"
partshttps://openvibe.network/contracts/ui/layout.v1.json#/$defs/partyes
  • minItems 1
  • maxItems 64
updated_atstring
  • format date-time

Examples

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

Valid: overlay-dock
{
  "surface": "bot.overlay",
  "surface_version": 1,
  "device": "computer",
  "name": "One-thumb overlay",
  "author": {
    "name": "Ana"
  },
  "sharing": "link",
  "parts": [
    {
      "id": "stop",
      "visible": true,
      "place": {
        "dock": "right",
        "order": 0,
        "w": 2,
        "h": 1
      },
      "style": {
        "tint": "danger",
        "shape": "round",
        "opacity": 1,
        "label": true
      },
      "bindings": {
        "keys": [
          "Space"
        ],
        "gamepad": [
          "south"
        ]
      }
    },
    {
      "id": "battery",
      "visible": true,
      "place": {
        "dock": "right",
        "order": 1,
        "w": 2,
        "h": 1
      },
      "style": {
        "tint": "surface",
        "shape": "pill",
        "opacity": 0.8,
        "label": false
      },
      "bindings": {
        "keys": [],
        "gamepad": []
      }
    }
  ]
}
Valid: phone-controls
{
  "surface": "bot.controls",
  "surface_version": 1,
  "device": "phone",
  "name": "My phone controls",
  "author": {
    "name": "Ana",
    "subject": {
      "type": "user",
      "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
    }
  },
  "sharing": "private",
  "parts": [
    {
      "id": "stop",
      "visible": true,
      "place": {
        "x": 0,
        "y": 0,
        "w": 1,
        "h": 1
      },
      "style": {
        "tint": "surface",
        "shape": "pill",
        "opacity": 1,
        "label": true
      },
      "bindings": {
        "keys": [
          "Space"
        ],
        "gamepad": [
          "south"
        ]
      }
    },
    {
      "id": "stick",
      "visible": true,
      "place": {
        "x": 0,
        "y": 1,
        "w": 4,
        "h": 3
      },
      "style": {
        "tint": "surface",
        "shape": "round",
        "opacity": 1,
        "label": false
      },
      "bindings": {
        "keys": [
          "W",
          "A",
          "S",
          "D"
        ],
        "gamepad": [
          "left-stick"
        ]
      }
    },
    {
      "id": "battery",
      "visible": true,
      "place": {
        "x": 0,
        "y": 4,
        "w": 2,
        "h": 1
      },
      "style": {
        "tint": "success",
        "shape": "pill",
        "opacity": 1,
        "label": true
      },
      "bindings": {
        "keys": [],
        "gamepad": []
      }
    },
    {
      "id": "latency",
      "visible": false,
      "place": {
        "x": 2,
        "y": 4,
        "w": 2,
        "h": 1
      },
      "style": {
        "tint": "muted",
        "shape": "pill",
        "opacity": 1,
        "label": true
      },
      "bindings": {
        "keys": [],
        "gamepad": []
      }
    }
  ],
  "updated_at": "2026-11-11T12:00:00.000Z"
}
Rejected: colour-tint
{
  "surface": "bot.controls",
  "surface_version": 1,
  "device": "phone",
  "name": "Bad tint",
  "author": {
    "name": "Ana"
  },
  "sharing": "private",
  "parts": [
    {
      "id": "stop",
      "visible": true,
      "place": {
        "x": 0,
        "y": 0,
        "w": 2,
        "h": 2
      },
      "style": {
        "tint": "#ff0000",
        "shape": "round",
        "opacity": 1,
        "label": true
      },
      "bindings": {
        "keys": [],
        "gamepad": []
      }
    }
  ]
}
Rejected: transparent
{
  "surface": "bot.controls",
  "surface_version": 1,
  "device": "phone",
  "name": "Too faint",
  "author": {
    "name": "Ana"
  },
  "sharing": "private",
  "parts": [
    {
      "id": "stop",
      "visible": true,
      "place": {
        "x": 0,
        "y": 0,
        "w": 2,
        "h": 2
      },
      "style": {
        "tint": "danger",
        "shape": "round",
        "opacity": 0.2,
        "label": true
      },
      "bindings": {
        "keys": [],
        "gamepad": []
      }
    }
  ]
}

Validate

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