{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://fluxygram.app/schema/v1.json",
  "title": "Fluxygram diagram",
  "description": "An animated diagram that explains something step by step.",
  "type": "object",
  "required": [
    "type",
    "nodes"
  ],
  "properties": {
    "$schema": {
      "type": "string"
    },
    "type": {
      "description": "Diagram type. Each one has its own default motion.",
      "enum": [
        "flow",
        "architecture",
        "timeline",
        "tree",
        "cycle",
        "sequence",
        "mindmap"
      ]
    },
    "title": {
      "type": "string",
      "description": "Shown above the diagram. Say what it shows."
    },
    "theme": {
      "enum": [
        "dark",
        "light"
      ],
      "default": "dark"
    },
    "direction": {
      "enum": [
        "LR",
        "TB"
      ],
      "default": "LR",
      "description": "Layout direction for flow diagrams."
    },
    "nodes": {
      "type": "array",
      "minItems": 1,
      "items": {
        "$ref": "#/$defs/node"
      }
    },
    "edges": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/edge"
      }
    },
    "groups": {
      "type": "array",
      "description": "Layers for architecture diagrams, listed top to bottom.",
      "items": {
        "$ref": "#/$defs/group"
      }
    },
    "steps": {
      "type": "array",
      "description": "Optional story. Steps are cumulative. Without steps, the type's default motion is used.",
      "items": {
        "$ref": "#/$defs/step"
      }
    },
    "finale": {
      "type": "boolean",
      "default": true,
      "description": "After the last step the camera zooms out and every visible connection flows at once. Set false to end on the last step."
    },
    "motion": {
      "type": "object",
      "additionalProperties": false,
      "description": "Default animation for the whole diagram. Blocks and connections can override enter / travel.",
      "properties": {
        "enter": {
          "enum": [
            "fade",
            "scale",
            "draw",
            "slide"
          ],
          "description": "How a block enters. fade: fades up (default). scale: grows with a slight bounce. draw: its outline is traced, then fill and text appear. slide: slides in."
        },
        "travel": {
          "enum": [
            "particle",
            "pulse",
            "dash",
            "packets"
          ],
          "description": "What travels along a connection when it flows. particle: comet dot (default). pulse: a stretch of light. dash: dashes marching continuously. packets: small spaced blocks."
        },
        "speed": {
          "enum": [
            "slow",
            "normal",
            "fast"
          ],
          "default": "normal"
        },
        "camera": {
          "enum": [
            "follow",
            "fixed"
          ],
          "default": "follow",
          "description": "follow: the camera follows the action. fixed: everything always in view."
        },
        "finale": {
          "type": "boolean",
          "default": true
        },
        "hold": {
          "type": "number",
          "minimum": 0.5,
          "maximum": 60,
          "description": "Seconds each step stays on screen during autoplay. Omit it to let Fluxygram time each step by its content."
        }
      }
    }
  },
  "$defs": {
    "id": {
      "type": "string",
      "minLength": 1,
      "pattern": "^[A-Za-z0-9_.:-]+$"
    },
    "ref": {
      "oneOf": [
        {
          "$ref": "#/$defs/id"
        },
        {
          "type": "array",
          "items": {
            "$ref": "#/$defs/id"
          }
        }
      ]
    },
    "node": {
      "type": "object",
      "required": [
        "id",
        "label"
      ],
      "additionalProperties": false,
      "properties": {
        "id": {
          "$ref": "#/$defs/id"
        },
        "label": {
          "type": "string",
          "description": "Short name, ideally 1 to 3 words."
        },
        "description": {
          "type": "string",
          "description": "One short line under the name."
        },
        "icon": {
          "description": "Built-in icon name.",
          "enum": [
            "check",
            "alert",
            "info",
            "help",
            "flag",
            "star",
            "heart",
            "bookmark",
            "tag",
            "pin",
            "home",
            "search",
            "settings",
            "filter",
            "clock",
            "calendar",
            "idea",
            "target",
            "trophy",
            "rocket",
            "zap",
            "layers",
            "workflow",
            "puzzle",
            "box",
            "user",
            "users",
            "verified",
            "signup",
            "admin",
            "bot",
            "contact",
            "deal",
            "building",
            "school",
            "hospital",
            "student",
            "work",
            "brain",
            "browser",
            "mobile",
            "tablet",
            "monitor",
            "laptop",
            "watch",
            "printer",
            "camera",
            "mic",
            "speaker",
            "keyboard",
            "gamepad",
            "tv",
            "router",
            "wifi",
            "bluetooth",
            "cpu",
            "disk",
            "usb",
            "server",
            "cloud",
            "database",
            "network",
            "globe",
            "cdn",
            "container",
            "api",
            "plug",
            "cable",
            "gauge",
            "activity",
            "queue",
            "balancer",
            "function",
            "storage",
            "backup",
            "sync",
            "upload",
            "download",
            "logs",
            "dashboard",
            "code",
            "terminal",
            "braces",
            "bug",
            "git",
            "merge",
            "pullrequest",
            "package",
            "tool",
            "build",
            "design",
            "pen",
            "file",
            "files",
            "folder",
            "image",
            "video",
            "music",
            "table",
            "sheet",
            "chart",
            "bars",
            "pie",
            "book",
            "notebook",
            "clipboard",
            "inbox",
            "cart",
            "card",
            "wallet",
            "money",
            "coins",
            "receipt",
            "store",
            "truck",
            "gift",
            "percent",
            "bank",
            "barcode",
            "scan",
            "scale",
            "mail",
            "message",
            "chat",
            "phone",
            "notification",
            "send",
            "share",
            "megaphone",
            "rss",
            "at",
            "link",
            "shield",
            "lock",
            "unlock",
            "key",
            "fingerprint",
            "eye",
            "hidden",
            "secure",
            "threat",
            "id",
            "sun",
            "moon",
            "leaf",
            "tree",
            "water",
            "fire",
            "mountain",
            "map",
            "plane",
            "car",
            "train",
            "ship",
            "factory",
            "warehouse",
            "health",
            "pill",
            "fitness",
            "food",
            "coffee",
            "play",
            "pause",
            "timer",
            "hourglass",
            "loading",
            "error",
            "add",
            "remove",
            "next",
            "join",
            "repeat",
            "random",
            "up",
            "down"
          ]
        },
        "kind": {
          "enum": [
            "default",
            "decision",
            "start",
            "end",
            "data",
            "database",
            "note"
          ],
          "description": "Block shape. decision: diamond (phrase it as a question). start/end: pill. data: parallelogram (input/output). database: cylinder. note: folded note for annotations."
        },
        "group": {
          "$ref": "#/$defs/id",
          "description": "architecture only: the layer this node belongs to."
        },
        "date": {
          "type": "string",
          "description": "timeline only, for example \"1995\" or \"2026-03\"."
        },
        "accent": {
          "type": "boolean",
          "description": "Highlight this node with the accent color."
        },
        "x": {
          "type": "number",
          "description": "Manually pinned position (top-left), set by the visual editor. Omit it to let Fluxygram place the node."
        },
        "y": {
          "type": "number",
          "description": "Manually pinned position (top-left). Use together with x."
        },
        "enter": {
          "enum": [
            "fade",
            "scale",
            "draw",
            "slide"
          ],
          "description": "How a block enters. fade: fades up (default). scale: grows with a slight bounce. draw: its outline is traced, then fill and text appear. slide: slides in."
        },
        "state": {
          "enum": [
            "success",
            "error",
            "warning",
            "pending",
            "default"
          ],
          "description": "State from the start (steps can change it). success: green + check. error: red, shakes. warning: amber, badge blinks. pending: in progress, dashed border spins."
        }
      }
    },
    "edge": {
      "type": "object",
      "required": [
        "from",
        "to"
      ],
      "additionalProperties": false,
      "properties": {
        "id": {
          "$ref": "#/$defs/id",
          "description": "Needed to reference the edge from steps. Defaults to \"from->to\"."
        },
        "from": {
          "$ref": "#/$defs/id"
        },
        "to": {
          "$ref": "#/$defs/id"
        },
        "label": {
          "type": "string"
        },
        "carries": {
          "type": "string",
          "description": "What travels along the edge. Shown next to the particle (\"token\", \"$\", \"event\"). 1 or 2 words."
        },
        "travel": {
          "enum": [
            "particle",
            "pulse",
            "dash",
            "packets"
          ],
          "description": "What travels along a connection when it flows. particle: comet dot (default). pulse: a stretch of light. dash: dashes marching continuously. packets: small spaced blocks."
        },
        "state": {
          "enum": [
            "success",
            "error",
            "warning",
            "pending",
            "default"
          ],
          "description": "State from the start. Colors the line, the particle and the label (e.g. a path that fails)."
        }
      }
    },
    "group": {
      "type": "object",
      "required": [
        "id",
        "label"
      ],
      "additionalProperties": false,
      "properties": {
        "id": {
          "$ref": "#/$defs/id"
        },
        "label": {
          "type": "string"
        }
      }
    },
    "step": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "show": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/id"
          },
          "description": "Elements that appear. Showing an edge also shows its two nodes."
        },
        "hide": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/id"
          }
        },
        "focus": {
          "$ref": "#/$defs/id",
          "description": "The camera moves in on this node or group."
        },
        "flow": {
          "$ref": "#/$defs/ref",
          "description": "Edges a particle travels along while the step is active."
        },
        "highlight": {
          "$ref": "#/$defs/ref",
          "description": "Elements that stand out; the rest dims."
        },
        "caption": {
          "type": "string",
          "description": "Text for the step. Keep it under 12 words."
        },
        "state": {
          "type": "object",
          "description": "Changes node or connection states from this step on: { \"pay\": \"success\", \"e3\": \"error\" }. \"default\" clears it.",
          "additionalProperties": {
            "enum": [
              "success",
              "error",
              "warning",
              "pending",
              "default"
            ]
          }
        },
        "duration": {
          "type": "number",
          "minimum": 0.5,
          "maximum": 60,
          "description": "Seconds this step stays on screen during autoplay (overrides motion.hold)."
        },
        "notes": {
          "type": "string",
          "description": "Speaker notes for this step. Shown only in the presenter view (/present), never in the diagram."
        }
      }
    }
  }
}
