{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Shot Specification",
  "description": "Per-shot cinematic specification conforming to the 5-part formula.",
  "type": "object",
  "required": [
    "id",
    "shot_type",
    "camera_movement",
    "subject",
    "action",
    "context",
    "style_ambiance",
    "duration"
  ],
  "properties": {
    "id": {
      "type": "string",
      "description": "Unique shot identifier, e.g. act1_scene01_shot03",
      "pattern": "^act[0-9]+_scene[0-9]+_shot[0-9]+$"
    },
    "shot_type": {
      "type": "string",
      "enum": [
        "wide",
        "establishing",
        "medium",
        "close_up",
        "extreme_close_up",
        "pov",
        "two_shot",
        "over_shoulder",
        "low_angle",
        "high_angle"
      ],
      "description": "The framing/type of the shot."
    },
    "camera_movement": {
      "type": "string",
      "enum": [
        "static",
        "dolly_in",
        "dolly_out",
        "pan_left",
        "pan_right",
        "tilt_up",
        "tilt_down",
        "tracking",
        "crane",
        "handheld",
        "arc",
        "rack_focus"
      ],
      "description": "Camera movement during the shot."
    },
    "temporal_effect": {
      "type": "string",
      "enum": [
        "normal",
        "slow_motion",
        "freeze_frame",
        "flash_cut",
        "time_lapse"
      ],
      "description": "Temporal effect applied to the shot.",
      "default": "normal"
    },
    "subject": {
      "type": "string",
      "description": "Who or what is in frame (Part 2 of the 5-part formula)."
    },
    "action": {
      "type": "string",
      "description": "What happens during the shot (Part 3)."
    },
    "context": {
      "type": "string",
      "description": "Where, when, surrounding elements (Part 4)."
    },
    "style_ambiance": {
      "type": "string",
      "description": "Visual mood, color grade, film stock feel (Part 5)."
    },
    "audio": {
      "type": "object",
      "description": "3-layer audio direction for Veo 3.1 native audio.",
      "properties": {
        "dialogue": {
          "type": ["string", "null"],
          "description": "Quoted dialogue text with tone/delivery notes. Null if no dialogue."
        },
        "sfx": {
          "type": ["string", "null"],
          "description": "Sound effects (prefix SFX:). Null if none."
        },
        "ambient": {
          "type": ["string", "null"],
          "description": "Environmental ambient sound (prefix AMB:). Null if none."
        }
      }
    },
    "duration": {
      "type": "integer",
      "enum": [4, 6, 8],
      "description": "Shot duration in seconds (Veo 3.1 limits)."
    },
    "frame_refs": {
      "type": "object",
      "description": "Frame reference paths for continuity and generation.",
      "properties": {
        "start_frame": {
          "type": ["string", "null"],
          "description": "Path to start frame image (from previous shot's last frame)."
        },
        "end_frame": {
          "type": ["string", "null"],
          "description": "Path to end frame image (for next shot's start frame)."
        },
        "reference_images": {
          "type": "array",
          "items": { "type": "string" },
          "description": "Paths to reference images from reference_registry for this shot."
        }
      }
    },
    "continuity": {
      "type": "object",
      "description": "Continuity metadata for scene assembly.",
      "properties": {
        "continues_from": {
          "type": ["string", "null"],
          "description": "ID of the shot this continues from."
        },
        "needs_frame_anchor": {
          "type": "boolean",
          "description": "Whether the next shot needs this shot's last frame.",
          "default": false
        },
        "is_montage_item": {
          "type": "boolean",
          "description": "Whether this shot is part of a montage (no frame-anchoring needed).",
          "default": false
        }
      }
    },
    "safety_reframe": {
      "type": "boolean",
      "description": "Whether this shot was reframed for safety filter compliance.",
      "default": false
    }
  }
}
