{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://theamateur.co.uk/schemas/dpl/dpl.shot-list-1.schema.json",
  "title": "DPL shot list for tools (dpl.shot-list/1)",
  "description": "What `dpl shot-list <plan> --format json` writes: every shot of a valid plan with its DPL camera terms and the industry terms they map to (MovieLabs Creative Vocabulary), plus the vocabulary's name, version and file hash. It is derived from the plan and adds nothing to it. Members are always written, null when the plan or the vocabulary has nothing to say; `picture` and `beat_functions` appear only when the plan declares them, and are the plan's own shapes.",
  "$comment": "Written by ShotList.Json (VideoEditor.DirectorialPlanning.Plan/ShotList.cs), which builds the document by hand, so this file is written by hand too. Tests run the real command line over the repository's plans and validate the output here, and the vocabulary terms are checked against IndustryMatch and the plan schema's definitions.",
  "type": "object",
  "properties": {
    "format": {
      "const": "dpl.shot-list/1"
    },
    "work": {
      "type": "string",
      "description": "The plan's work.id."
    },
    "vocabulary": {
      "type": "object",
      "description": "The industry vocabulary the terms were mapped with.",
      "properties": {
        "name": {
          "type": "string"
        },
        "version": {
          "type": "string"
        },
        "source_sha256": {
          "type": "string",
          "description": "SHA-256 of the published vocabulary file the mapping was made against.",
          "pattern": "^[0-9a-f]{64}$"
        }
      },
      "required": [
        "name",
        "version",
        "source_sha256"
      ],
      "additionalProperties": false
    },
    "shots": {
      "type": "array",
      "description": "Every shot of every scene, in plan order.",
      "items": {
        "$ref": "#/$defs/ShotRow"
      }
    },
    "beat_functions": {
      "type": "array",
      "description": "The plan's sound.beat_functions, unchanged. Present only when the plan declares some.",
      "items": {
        "$ref": "https://theamateur.co.uk/schemas/dpl/dpl.plan-1.schema.json#/$defs/BeatFunction"
      }
    }
  },
  "required": [
    "format",
    "work",
    "vocabulary",
    "shots"
  ],
  "additionalProperties": false,
  "$defs": {
    "ShotRow": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string"
        },
        "scene": {
          "type": "string",
          "description": "The id of the scene the shot belongs to."
        },
        "start_ms": {
          "type": "integer"
        },
        "end_ms": {
          "type": "integer"
        },
        "purpose": {
          "type": "string"
        },
        "subject": {
          "type": "string"
        },
        "camera": {
          "$ref": "#/$defs/CameraRow"
        },
        "picture": {
          "$ref": "https://theamateur.co.uk/schemas/dpl/dpl.plan-1.schema.json#/$defs/ShotPicture",
          "description": "The shot's picture, as the plan states it. Present only when the plan gives one."
        }
      },
      "required": [
        "id",
        "scene",
        "start_ms",
        "end_ms",
        "purpose",
        "subject",
        "camera"
      ],
      "additionalProperties": false
    },
    "CameraRow": {
      "type": "object",
      "properties": {
        "size": {
          "$ref": "#/$defs/SizeTerm"
        },
        "angle": {
          "anyOf": [
            {
              "$ref": "#/$defs/AngleTerm"
            },
            {
              "type": "null"
            }
          ]
        },
        "movement": {
          "$ref": "#/$defs/MovementTerm"
        },
        "lens": {
          "anyOf": [
            {
              "$ref": "#/$defs/LensTerm"
            },
            {
              "type": "null"
            }
          ]
        },
        "perspective": {
          "description": "DPL's own term; the industry vocabulary has no category for it.",
          "anyOf": [
            {
              "$ref": "https://theamateur.co.uk/schemas/dpl/dpl.plan-1.schema.json#/$defs/Perspective"
            },
            {
              "type": "null"
            }
          ]
        },
        "focal": {
          "description": "Short-form profile: present only when the shot names a camera lens in millimetres (camera.focal_mm). The nearest industry lens class by the vocabulary's own focal-length ranges, always an approximate match.",
          "$ref": "#/$defs/FocalTerm"
        }
      },
      "required": [
        "size",
        "angle",
        "movement",
        "lens",
        "perspective"
      ],
      "additionalProperties": false
    },
    "SizeTerm": {
      "type": "object",
      "description": "A shot size in DPL's term and the industry's.",
      "properties": {
        "dpl": {
          "$ref": "https://theamateur.co.uk/schemas/dpl/dpl.plan-1.schema.json#/$defs/ShotSize"
        },
        "industry": {
          "anyOf": [
            {
              "$ref": "#/$defs/SizeIndustryTerm"
            },
            {
              "type": "null"
            }
          ]
        },
        "match": {
          "$ref": "#/$defs/IndustryMatch"
        },
        "note": {
          "type": [
            "string",
            "null"
          ],
          "description": "What differs, for an approximate match."
        }
      },
      "required": [
        "dpl",
        "industry",
        "match",
        "note"
      ],
      "additionalProperties": false
    },
    "AngleTerm": {
      "type": "object",
      "description": "A camera angle in DPL's term and the industry's.",
      "properties": {
        "dpl": {
          "$ref": "https://theamateur.co.uk/schemas/dpl/dpl.plan-1.schema.json#/$defs/CameraAngle"
        },
        "industry": {
          "anyOf": [
            {
              "$ref": "#/$defs/AngleIndustryTerm"
            },
            {
              "type": "null"
            }
          ]
        },
        "match": {
          "$ref": "#/$defs/IndustryMatch"
        },
        "note": {
          "type": [
            "string",
            "null"
          ]
        }
      },
      "required": [
        "dpl",
        "industry",
        "match",
        "note"
      ],
      "additionalProperties": false
    },
    "MovementTerm": {
      "type": "object",
      "description": "A camera movement in DPL's term and the industry's.",
      "properties": {
        "dpl": {
          "$ref": "https://theamateur.co.uk/schemas/dpl/dpl.plan-1.schema.json#/$defs/CameraMovement"
        },
        "industry": {
          "anyOf": [
            {
              "$ref": "#/$defs/MovementIndustryTerm"
            },
            {
              "type": "null"
            }
          ]
        },
        "match": {
          "$ref": "#/$defs/IndustryMatch"
        },
        "note": {
          "type": [
            "string",
            "null"
          ]
        }
      },
      "required": [
        "dpl",
        "industry",
        "match",
        "note"
      ],
      "additionalProperties": false
    },
    "LensTerm": {
      "type": "object",
      "description": "A lens in DPL's term and the industry's.",
      "properties": {
        "dpl": {
          "$ref": "https://theamateur.co.uk/schemas/dpl/dpl.plan-1.schema.json#/$defs/Lens"
        },
        "industry": {
          "anyOf": [
            {
              "$ref": "#/$defs/LensIndustryTerm"
            },
            {
              "type": "null"
            }
          ]
        },
        "match": {
          "$ref": "#/$defs/IndustryMatch"
        },
        "note": {
          "type": [
            "string",
            "null"
          ]
        }
      },
      "required": [
        "dpl",
        "industry",
        "match",
        "note"
      ],
      "additionalProperties": false
    },
    "FocalTerm": {
      "type": "object",
      "description": "A camera lens named in millimetres, with the full-frame equivalent (the lens's mm times the sensor's crop factor) and the industry lens class that focal length falls in.",
      "properties": {
        "mm": {
          "type": "number",
          "description": "The lens's focal length, as the plan says it."
        },
        "equivalent_mm": {
          "type": "number",
          "description": "The full-frame equivalent focal length, to one decimal."
        },
        "industry": {
          "$ref": "#/$defs/LensIndustryTerm"
        },
        "match": {
          "$ref": "#/$defs/IndustryMatch"
        },
        "note": {
          "type": [
            "string",
            "null"
          ],
          "description": "What differs: the vocabulary defines lens classes by focal length 'typically'."
        }
      },
      "required": [
        "mm",
        "equivalent_mm",
        "industry",
        "match",
        "note"
      ],
      "additionalProperties": false
    },
    "IndustryMatch": {
      "type": "string",
      "description": "How close the industry term is: the same idea, the nearest term (with a note), or no term in the vocabulary (industry is then null).",
      "enum": [
        "exact",
        "approximate",
        "none"
      ]
    },
    "SizeIndustryTerm": {
      "type": "object",
      "properties": {
        "category": {
          "const": "shot-size"
        },
        "slug": {
          "type": "string"
        },
        "term": {
          "type": "string"
        }
      },
      "required": [
        "category",
        "slug",
        "term"
      ],
      "additionalProperties": false
    },
    "AngleIndustryTerm": {
      "type": "object",
      "properties": {
        "category": {
          "const": "camera-angle"
        },
        "slug": {
          "type": "string"
        },
        "term": {
          "type": "string"
        }
      },
      "required": [
        "category",
        "slug",
        "term"
      ],
      "additionalProperties": false
    },
    "MovementIndustryTerm": {
      "type": "object",
      "properties": {
        "category": {
          "const": "camera-movement"
        },
        "slug": {
          "type": "string"
        },
        "term": {
          "type": "string"
        }
      },
      "required": [
        "category",
        "slug",
        "term"
      ],
      "additionalProperties": false
    },
    "LensIndustryTerm": {
      "type": "object",
      "properties": {
        "category": {
          "const": "lens"
        },
        "slug": {
          "type": "string"
        },
        "term": {
          "type": "string"
        }
      },
      "required": [
        "category",
        "slug",
        "term"
      ],
      "additionalProperties": false
    }
  }
}
