{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://obpal.blackboxes.net/profile.schema.json",
  "title": "ob.Pal controller profile",
  "description": "A named set of motion settings, and optionally button bindings, a phone applies (CATALOGUE §3). Check one with checkProfile() in @obpal/core, then add it as catalogue/profiles/<id>.json in https://github.com/Axialon/obpal.",
  "type": "object",
  "required": [
    "id",
    "name",
    "for",
    "on",
    "aim",
    "steer",
    "point"
  ],
  "additionalProperties": false,
  "properties": {
    "id": {
      "type": "string",
      "pattern": "^[a-z][a-z0-9-]{1,31}$",
      "not": {
        "enum": [
          "default",
          "flight",
          "driving",
          "shooter",
          "pointer"
        ]
      },
      "description": "New, lowercase, and the file name"
    },
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 40
    },
    "for": {
      "type": "string",
      "minLength": 1,
      "maxLength": 120,
      "description": "What it is for, one line"
    },
    "on": {
      "type": "array",
      "uniqueItems": true,
      "items": {
        "enum": [
          "motion.aim",
          "motion.steer",
          "motion.point"
        ]
      },
      "description": "Utilities it switches on when it applies"
    },
    "aim": {
      "type": "object",
      "required": [
        "route",
        "gain",
        "curve",
        "deadzone",
        "invertY",
        "edgeTurn"
      ],
      "additionalProperties": false,
      "properties": {
        "route": {
          "enum": [
            "stick.right",
            "stick.left",
            "mouse"
          ],
          "description": "Where this motion goes (CATALOGUE §2)"
        },
        "gain": {
          "type": "number",
          "minimum": 0.25,
          "maximum": 4,
          "description": "Sensitivity"
        },
        "curve": {
          "type": "number",
          "minimum": 0.5,
          "maximum": 3,
          "description": "Above 1 is finer near the centre"
        },
        "deadzone": {
          "type": "number",
          "minimum": 0,
          "maximum": 0.5,
          "description": "The game’s own stick deadzone to jump over"
        },
        "invertY": {
          "type": "boolean"
        },
        "edgeTurn": {
          "type": "boolean",
          "description": "Point only: near a screen edge the right stick turns toward it"
        }
      }
    },
    "steer": {
      "type": "object",
      "required": [
        "route",
        "gain",
        "curve",
        "deadzone",
        "invertY",
        "edgeTurn"
      ],
      "additionalProperties": false,
      "properties": {
        "route": {
          "enum": [
            "stick.wheel",
            "stick.fly",
            "stick.left",
            "stick.right"
          ],
          "description": "Where this motion goes (CATALOGUE §2)"
        },
        "gain": {
          "type": "number",
          "minimum": 0.25,
          "maximum": 4,
          "description": "Sensitivity"
        },
        "curve": {
          "type": "number",
          "minimum": 0.5,
          "maximum": 3,
          "description": "Above 1 is finer near the centre"
        },
        "deadzone": {
          "type": "number",
          "minimum": 0,
          "maximum": 0.5,
          "description": "The game’s own stick deadzone to jump over"
        },
        "invertY": {
          "type": "boolean"
        },
        "edgeTurn": {
          "type": "boolean",
          "description": "Point only: near a screen edge the right stick turns toward it"
        }
      }
    },
    "point": {
      "type": "object",
      "required": [
        "route",
        "gain",
        "curve",
        "deadzone",
        "invertY",
        "edgeTurn"
      ],
      "additionalProperties": false,
      "properties": {
        "route": {
          "enum": [
            "pointer"
          ],
          "description": "Where this motion goes (CATALOGUE §2)"
        },
        "gain": {
          "type": "number",
          "minimum": 0.25,
          "maximum": 4,
          "description": "Sensitivity"
        },
        "curve": {
          "type": "number",
          "minimum": 0.5,
          "maximum": 3,
          "description": "Above 1 is finer near the centre"
        },
        "deadzone": {
          "type": "number",
          "minimum": 0,
          "maximum": 0.5,
          "description": "The game’s own stick deadzone to jump over"
        },
        "invertY": {
          "type": "boolean"
        },
        "edgeTurn": {
          "type": "boolean",
          "description": "Point only: near a screen edge the right stick turns toward it"
        }
      }
    },
    "controller": {
      "enum": [
        "face.gamepad",
        "face.wheel",
        "face.wii",
        "face.mouse",
        "face.trackpad",
        "face.hand",
        "face.keyboard",
        "face.drums",
        "face.keys"
      ],
      "description": "The controller it tunes (CATALOGUE §9.1); absent: face.gamepad"
    },
    "buttons": {
      "type": "object",
      "maxProperties": 32,
      "propertyNames": {
        "pattern": "^(key:(#\\d{1,3}|[A-Za-z0-9]{1,32})|media:[a-z]{2,24}|pad:(raw:)?(b\\d{1,2}|a\\d{1,2}[+-])|back)$"
      },
      "additionalProperties": {
        "type": "string",
        "pattern": "^(none|tray:\\S{1,40}|app:(gyro|recentre|next|prev|keyboard)|[a-z][a-z0-9]{0,15}|key-[A-Za-z]{1,16})$"
      },
      "description": "Physical inputs (key:<code>, media:<action>, pad:b<i>, back) bound to the controller’s controls (its `controls` in catalogue.json), a key on the screen (key-<code>), tray:<id>, app:<action> or none. Only what differs from its defaults (CATALOGUE §3)."
    }
  }
}