{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://www.moldraw.com/demos/schema.json",
  "title": "MolDraw interactive demo",
  "description": "A step-by-step walkthrough played by <moldraw-demo> on a lightweight copy of the MolDraw editor UI. Each step moves a cursor to a UI element (target), performs an action (hover, click, type, key), shows a caption, and changes the UI state (set). Steps run in order; the state after step N is `initial` plus every `set` of steps 0..N. Write captions in plain, short sentences. Guide for authors and LLMs: https://www.moldraw.com/demos/llms.txt",
  "type": "object",
  "required": [
    "id",
    "title",
    "steps"
  ],
  "additionalProperties": false,
  "properties": {
    "$schema": {
      "type": "string"
    },
    "id": {
      "type": "string",
      "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
      "description": "Kebab-case id; also the file name (/demos/<id>.json)."
    },
    "title": {
      "type": "string",
      "maxLength": 80,
      "description": "What the demo teaches, e.g. \"Turn on the canvas grid\"."
    },
    "description": {
      "type": "string",
      "maxLength": 300,
      "description": "One or two sentences for listings and search."
    },
    "article": {
      "type": "string",
      "format": "uri",
      "description": "Optional URL of the article this demo belongs to."
    },
    "appVersionNote": {
      "type": "string",
      "description": "Optional note about which MolDraw UI this matches (for keeping demos current)."
    },
    "autoplay": {
      "type": "boolean",
      "default": true,
      "description": "Start playing when scrolled into view."
    },
    "loop": {
      "type": "boolean",
      "default": true,
      "description": "Restart after the last step."
    },
    "initial": {
      "$ref": "#/$defs/state",
      "description": "UI state before step 1. Omitted keys use the defaults."
    },
    "steps": {
      "type": "array",
      "minItems": 1,
      "maxItems": 30,
      "items": {
        "$ref": "#/$defs/step"
      }
    }
  },
  "$defs": {
    "target": {
      "type": "string",
      "description": "UI element the cursor goes to and the highlight ring surrounds.",
      "enum": [
        "app",
        "topbar.search",
        "topbar.theme",
        "topbar.grid",
        "topbar.signin",
        "topbar.more",
        "toolbar.menu",
        "toolbar.undo",
        "toolbar.redo",
        "toolbar.cleanup",
        "toolbar.3d",
        "toolbar.text",
        "toolbar.settings",
        "toolbar.zoomIn",
        "toolbar.zoomOut",
        "toolbar.fit",
        "toolbar.download",
        "rail.hand",
        "rail.select",
        "rail.erase",
        "rail.bond",
        "rail.ring",
        "rail.text",
        "rail.arrow",
        "canvas",
        "canvas.structure",
        "settings",
        "settings.close",
        "settings.nav.general",
        "settings.nav.style",
        "settings.nav.shortcuts",
        "settings.showGrid",
        "settings.snapToGrid",
        "settings.guides",
        "settings.snapCurvedArrows",
        "palette",
        "palette.input",
        "palette.result.0",
        "palette.result.1",
        "palette.result.2",
        "toast"
      ]
    },
    "state": {
      "type": "object",
      "additionalProperties": false,
      "description": "UI state of the editor copy. Only listed keys exist.",
      "properties": {
        "theme": {
          "enum": [
            "light",
            "dark"
          ],
          "default": "light"
        },
        "grid": {
          "type": "boolean",
          "default": false,
          "description": "Canvas grid visible (top-bar grid button and Settings > Show grid)."
        },
        "snap": {
          "type": "boolean",
          "default": false,
          "description": "Settings > Snap to grid."
        },
        "guides": {
          "type": "boolean",
          "default": true,
          "description": "Settings > Canvas assistance guidelines."
        },
        "arrowSnap": {
          "type": "boolean",
          "default": true,
          "description": "Settings > Snap curved arrows."
        },
        "settingsOpen": {
          "type": "boolean",
          "default": false,
          "description": "Settings dialog open (a bottom sheet on phones)."
        },
        "paletteOpen": {
          "type": "boolean",
          "default": false,
          "description": "Command palette (Ctrl+K) open."
        },
        "paletteQuery": {
          "type": "string",
          "default": "",
          "description": "Text in the palette search box. Prefer a `type` step to animate typing."
        },
        "paletteActive": {
          "type": "integer",
          "minimum": 0,
          "maximum": 4,
          "default": 0,
          "description": "Highlighted palette result."
        },
        "tool": {
          "enum": [
            "hand",
            "select",
            "erase",
            "bond",
            "ring",
            "text",
            "arrow"
          ],
          "default": "bond",
          "description": "Active tool on the left rail."
        },
        "structure": {
          "enum": [
            "aspirin",
            "benzene",
            "phenol",
            "ethanol",
            ""
          ],
          "default": "aspirin",
          "description": "Structure drawn on the canvas; empty string for a blank canvas."
        },
        "toast": {
          "type": "string",
          "default": "",
          "description": "Short status message at the bottom of the canvas; empty string hides it."
        }
      }
    },
    "step": {
      "type": "object",
      "required": [
        "title",
        "text"
      ],
      "additionalProperties": false,
      "properties": {
        "title": {
          "type": "string",
          "maxLength": 60,
          "description": "Short step heading, imperative: \"Click the grid button\"."
        },
        "text": {
          "type": "string",
          "maxLength": 240,
          "description": "One or two plain sentences. **bold** and `code` are supported."
        },
        "device": {
          "enum": [
            "desktop",
            "touch"
          ],
          "description": "Show this step only on desktop (mouse, wide screen) or touch (phones and tablets, where MolDraw uses its compact layout). Omit for all devices. Use it when the real UI differs, e.g. a top-bar button that phones do not have."
        },
        "target": {
          "$ref": "#/$defs/target"
        },
        "action": {
          "enum": [
            "none",
            "hover",
            "click",
            "type",
            "key"
          ],
          "default": "none",
          "description": "none: caption only. hover: cursor rests on target and shows its tooltip. click: cursor clicks target, then `set` applies. type: types `input` into the palette search box. key: shows the `keys` chips (keyboard shortcut), then `set` applies."
        },
        "tooltip": {
          "type": "string",
          "description": "Tooltip text for hover (defaults to the element's own tooltip)."
        },
        "input": {
          "type": "string",
          "maxLength": 40,
          "description": "Text typed by a `type` step."
        },
        "keys": {
          "type": "array",
          "items": {
            "type": "string",
            "maxLength": 12
          },
          "maxItems": 4,
          "description": "Keys shown by a `key` step, e.g. [\"Ctrl\", \"K\"]."
        },
        "set": {
          "$ref": "#/$defs/state",
          "description": "State changes this step makes (after its action)."
        },
        "highlight": {
          "type": "boolean",
          "default": true,
          "description": "Draw the orange ring around the target."
        },
        "durationMs": {
          "type": "integer",
          "minimum": 600,
          "maximum": 10000,
          "description": "How long the step stays before the next one (default depends on text length)."
        }
      },
      "allOf": [
        {
          "if": {
            "properties": {
              "action": {
                "const": "type"
              }
            },
            "required": [
              "action"
            ]
          },
          "then": {
            "required": [
              "input"
            ]
          }
        },
        {
          "if": {
            "properties": {
              "action": {
                "const": "key"
              }
            },
            "required": [
              "action"
            ]
          },
          "then": {
            "required": [
              "keys"
            ]
          }
        },
        {
          "if": {
            "properties": {
              "action": {
                "enum": [
                  "hover",
                  "click"
                ]
              }
            },
            "required": [
              "action"
            ]
          },
          "then": {
            "required": [
              "target"
            ]
          }
        }
      ]
    }
  }
}
