{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://vclaw.dev/schemas/video/artifacts/reframe-plan.schema.json",
  "title": "ReframePlan",
  "description": "Deterministic shot-by-shot crop, subject-anchor, hold-policy and caption contract for social video variants.",
  "type": "object",
  "required": ["schemaVersion", "sourcePath", "target", "shots"],
  "additionalProperties": false,
  "properties": {
    "schemaVersion": { "const": 1 },
    "sourcePath": { "type": "string", "minLength": 1 },
    "defaultHoldPolicy": { "enum": ["forbid", "allow"], "default": "forbid" },
    "target": {
      "type": "object",
      "required": ["aspectRatio", "width", "height"],
      "additionalProperties": false,
      "properties": {
        "aspectRatio": { "enum": ["9:16", "1:1"] },
        "width": { "type": "integer", "minimum": 2 },
        "height": { "type": "integer", "minimum": 2 }
      }
    },
    "shots": {
      "type": "array",
      "minItems": 1,
      "items": { "$ref": "#/definitions/shot" }
    },
    "captions": { "$ref": "#/definitions/captions" }
  },
  "definitions": {
    "anchor": {
      "type": "object",
      "required": ["x", "y"],
      "additionalProperties": false,
      "properties": {
        "x": { "type": "number", "minimum": 0 },
        "y": { "type": "number", "minimum": 0 },
        "verified": { "type": "boolean", "default": true },
        "endX": { "type": "number", "minimum": 0 },
        "endY": { "type": "number", "minimum": 0 },
        "width": { "type": "number", "exclusiveMinimum": 0 },
        "height": { "type": "number", "exclusiveMinimum": 0 }
      }
    },
    "subject": {
      "type": "object",
      "required": ["kind", "label"],
      "additionalProperties": false,
      "properties": {
        "kind": { "enum": ["person", "vehicle", "object", "group", "none"] },
        "label": { "type": "string", "minLength": 1 },
        "anchor": { "$ref": "#/definitions/anchor" }
      }
    },
    "crop": {
      "oneOf": [
        {
          "type": "object",
          "required": ["mode", "x", "y"],
          "additionalProperties": false,
          "properties": {
            "mode": { "const": "fixed" },
            "x": { "type": "number", "minimum": 0 },
            "y": { "type": "number", "minimum": 0 }
          }
        },
        {
          "type": "object",
          "required": ["mode", "startX", "endX", "startY", "endY"],
          "additionalProperties": false,
          "properties": {
            "mode": { "const": "linear" },
            "startX": { "type": "number", "minimum": 0 },
            "endX": { "type": "number", "minimum": 0 },
            "startY": { "type": "number", "minimum": 0 },
            "endY": { "type": "number", "minimum": 0 }
          }
        },
        {
          "type": "object",
          "required": ["mode"],
          "additionalProperties": false,
          "properties": { "mode": { "const": "contain" } }
        }
      ]
    },
    "shot": {
      "type": "object",
      "required": ["startSeconds", "endSeconds", "subject", "crop"],
      "additionalProperties": false,
      "properties": {
        "startSeconds": { "type": "number", "minimum": 0 },
        "endSeconds": { "type": "number", "exclusiveMinimum": 0 },
        "sourceStartSeconds": { "type": "number", "minimum": 0 },
        "sourceEndSeconds": { "type": "number", "exclusiveMinimum": 0 },
        "subject": { "$ref": "#/definitions/subject" },
        "crop": { "$ref": "#/definitions/crop" },
        "centerTolerancePercent": { "type": "number", "minimum": 0, "maximum": 50 },
        "allowTightCrop": { "type": "boolean" },
        "allowHold": { "type": "boolean" },
        "holdSeconds": { "type": "number", "minimum": 0 },
        "note": { "type": "string", "minLength": 1 }
      }
    },
    "captions": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "sourcePath": { "type": "string", "minLength": 1 },
        "profile": { "enum": ["social-large", "social-standard"] },
        "burnIn": { "type": "boolean" },
        "allowBurnedCaptionSource": { "type": "boolean" }
      }
    }
  }
}
