{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "slidetemplate-element.schema.json",
  "title": "Slide Template Element",
  "type": "object",
  "description": "One element on a slide template, positioned absolutely on the canvas. Maps 1:1 to the Doolittle slide element contract. A type of null marks an author-fillable element that carries a slot; a non-null type (e.g. 'shape') is pre-filled decoration.",
  "required": [ "id", "x", "y", "w", "h", "z" ],
  "properties": {
    "id": {
      "type": "string",
      "minLength": 1,
      "description": "Stable element id within the template (e.g. 'title', 'activity_card_bg')."
    },
    "type": {
      "type": [ "string", "null" ],
      "description": "Element type discriminator. null for an unfilled slot; otherwise a concrete type such as 'shape'."
    },
    "x": {
      "type": "integer",
      "description": "Left edge in pixels."
    },
    "y": {
      "type": "integer",
      "description": "Top edge in pixels."
    },
    "w": {
      "type": "integer",
      "minimum": 0,
      "description": "Width in pixels."
    },
    "h": {
      "type": "integer",
      "minimum": 0,
      "description": "Height in pixels."
    },
    "z": {
      "type": "integer",
      "description": "Stacking order."
    },
    "rotation": {
      "type": "number",
      "description": "Clockwise rotation in degrees."
    },
    "style": {
      "type": "string",
      "description": "Opaque JSON-encoded style string; stored and rendered as-is by CTK."
    },
    "properties": {
      "type": "string",
      "description": "Opaque JSON-encoded properties string; stored and rendered as-is by CTK."
    },
    "slot": { "$ref": "slidetemplate-slot.schema.json" }
  }
}
