{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://living-code.dev/port.schema.json",
  "title": "Living Code port",
  "description": "Opt a public living-code-theme repository into the landing by committing port.json and README.md at its root.",
  "type": "object",
  "additionalProperties": false,
  "required": ["schemaVersion", "name", "group", "flavors", "images"],
  "properties": {
    "$schema": { "type": "string", "maxLength": 300 },
    "schemaVersion": { "const": 1 },
    "name": { "type": "string", "minLength": 1, "maxLength": 80, "pattern": "^[^\\u0000-\\u001f\\u007f]+$" },
    "slug": { "type": "string", "minLength": 1, "maxLength": 64, "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$" },
    "group": { "type": "string", "minLength": 1, "maxLength": 60, "pattern": "^[A-Za-z0-9][A-Za-z0-9 &+/-]*$" },
    "description": { "type": "string", "minLength": 40, "maxLength": 300, "pattern": "^[^\\u0000-\\u001f\\u007f]+$" },
    "homepage": { "type": "string", "maxLength": 300, "pattern": "^https://[^\\s]+$" },
    "quick": { "type": "string", "minLength": 1, "maxLength": 120, "pattern": "^[^\\u0000-\\u001f\\u007f]+$" },
    "icon": { "type": "string", "maxLength": 80, "pattern": "^[a-z0-9]+$" },
    "emoji": { "description": "A single port-specific emoji (or non-ASCII symbol such as π) for its README title. The chameleon mascot belongs to Living Code branding.", "type": "string", "minLength": 1, "maxLength": 20, "pattern": "^[^\\u0000-\\u001f\\u007f]+$" },
    "aliases": {
      "type": "array", "maxItems": 20, "uniqueItems": true,
      "items": { "type": "string", "minLength": 1, "maxLength": 60, "pattern": "^[^\\u0000-\\u001f\\u007f]+$" }
    },
    "flavors": {
      "type": "array", "minItems": 1, "maxItems": 4, "uniqueItems": true,
      "items": { "enum": ["night", "frost", "paper", "signal"] }
    },
    "files": {
      "description": "Optional repository-relative files to link in the landing's What you get section.",
      "type": "array", "maxItems": 100, "uniqueItems": true,
      "items": { "$ref": "#/definitions/path" }
    },
    "images": {
      "description": "Real application screenshots. Use an empty array if no captures are available.",
      "type": "array", "maxItems": 4,
      "items": {
        "type": "object", "additionalProperties": false,
        "required": ["flavor", "path", "alt"],
        "properties": {
          "flavor": { "enum": ["night", "frost", "paper", "signal"] },
          "path": { "$ref": "#/definitions/path" },
          "alt": { "type": "string", "minLength": 1, "maxLength": 300, "pattern": "^[^\\u0000-\\u001f\\u007f]+$" }
        }
      }
    }
  },
  "definitions": {
    "path": {
      "type": "string", "minLength": 1, "maxLength": 240,
      "pattern": "^[A-Za-z0-9_.-][A-Za-z0-9_./ -]*$"
    }
  }
}
