{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://openfloorplan.app/plan-format.schema.json",
  "title": "Open Floor Plan plan",
  "description": "A lenient agent plan, or a full floorplanner.plan version 1 file. Lengths are millimetres, x increases to the right, and y increases downward.",
  "$defs": {
    "point": {
      "description": "A point in millimetres.",
      "oneOf": [
        {
          "type": "array",
          "prefixItems": [
            {
              "type": "number"
            },
            {
              "type": "number"
            }
          ],
          "items": false,
          "minItems": 2,
          "maxItems": 2
        },
        {
          "$ref": "#/$defs/storedPoint"
        }
      ]
    },
    "storedPoint": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "x",
        "y"
      ],
      "properties": {
        "x": {
          "type": "number"
        },
        "y": {
          "type": "number"
        }
      }
    },
    "wallRef": {
      "description": "A wall index from 0, or a wall id.",
      "oneOf": [
        {
          "type": "integer",
          "minimum": 0
        },
        {
          "type": "string",
          "minLength": 1
        }
      ]
    },
    "wall": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "a",
        "b"
      ],
      "properties": {
        "a": {
          "$ref": "#/$defs/point"
        },
        "b": {
          "$ref": "#/$defs/point"
        },
        "thickness": {
          "description": "Wall thickness in millimetres. Omit to use 100.",
          "type": "number",
          "exclusiveMinimum": 0
        }
      }
    },
    "polygonRoom": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "polygon"
      ],
      "properties": {
        "name": {
          "type": "string",
          "minLength": 1
        },
        "polygon": {
          "type": "array",
          "minItems": 3,
          "items": {
            "$ref": "#/$defs/point"
          }
        }
      }
    },
    "atRoom": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "at"
      ],
      "properties": {
        "name": {
          "type": "string",
          "minLength": 1
        },
        "at": {
          "description": "A point inside a room enclosed by the walls.",
          "$ref": "#/$defs/point"
        }
      }
    },
    "door": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "wall"
      ],
      "properties": {
        "wall": {
          "$ref": "#/$defs/wallRef"
        },
        "center": {
          "description": "Distance in millimetres from wall end a to the centre.",
          "type": "number"
        },
        "width": {
          "type": "number",
          "exclusiveMinimum": 0
        },
        "height": {
          "type": "number",
          "exclusiveMinimum": 0
        },
        "type": {
          "enum": [
            "single",
            "double",
            "sliding"
          ]
        },
        "hinge": {
          "enum": [
            "left",
            "right"
          ]
        },
        "swing": {
          "enum": [
            "in",
            "out"
          ]
        }
      }
    },
    "window": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "wall"
      ],
      "properties": {
        "wall": {
          "$ref": "#/$defs/wallRef"
        },
        "center": {
          "type": "number"
        },
        "width": {
          "type": "number",
          "exclusiveMinimum": 0
        },
        "height": {
          "type": "number",
          "exclusiveMinimum": 0
        },
        "sill": {
          "type": "number",
          "minimum": 0
        },
        "type": {
          "enum": [
            "standard",
            "bay"
          ]
        },
        "depth": {
          "description": "Bay depth in millimetres.",
          "type": "number",
          "exclusiveMinimum": 0
        },
        "angle": {
          "description": "Bay angle. 45 is splayed, 90 is a box bay.",
          "enum": [
            45,
            90
          ]
        },
        "side": {
          "enum": [
            "in",
            "out"
          ]
        }
      }
    },
    "furniture": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id"
      ],
      "dependentRequired": {
        "x": [
          "y"
        ],
        "y": [
          "x"
        ]
      },
      "properties": {
        "id": {
          "enum": [
            "single-bed",
            "double-bed",
            "king-bed",
            "sofa",
            "armchair",
            "dining-table",
            "dining-chair",
            "coffee-table",
            "desk",
            "wardrobe",
            "fridge",
            "toilet",
            "bath",
            "basin",
            "wall-mounted-tv",
            "tv-on-stand",
            "tv-unit",
            "bookcase",
            "sideboard",
            "2-seat-sofa",
            "ottoman",
            "rug",
            "floor-lamp",
            "plant",
            "fridge-freezer",
            "dishwasher",
            "washing-machine",
            "tumble-dryer",
            "range-cooker",
            "kitchen-island",
            "bar-stool",
            "chest-of-drawers",
            "bedside-table",
            "cot-bed",
            "desk-chair",
            "filing-cabinet",
            "radiator",
            "shower-tray",
            "upright-piano",
            "garden-table",
            "custom"
          ]
        },
        "x": {
          "type": "number"
        },
        "y": {
          "type": "number"
        },
        "rotation": {
          "description": "Degrees clockwise.",
          "type": "number"
        },
        "width": {
          "type": "number",
          "exclusiveMinimum": 0
        },
        "depth": {
          "type": "number",
          "exclusiveMinimum": 0
        },
        "height": {
          "description": "Vertical height in millimetres.",
          "type": "number",
          "exclusiveMinimum": 0
        }
      }
    },
    "agentPlan": {
      "type": "object",
      "additionalProperties": false,
      "description": "Walls or room polygons are enough. Doors, windows, and furniture are optional.",
      "properties": {
        "name": {
          "type": "string",
          "minLength": 1
        },
        "units": {
          "enum": [
            "metric",
            "imperial"
          ]
        },
        "ceilingHeight": {
          "type": "number",
          "minimum": 1800,
          "maximum": 6000
        },
        "walls": {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/wall"
          }
        },
        "rooms": {
          "type": "array",
          "minItems": 1,
          "items": {
            "oneOf": [
              {
                "$ref": "#/$defs/polygonRoom"
              },
              {
                "$ref": "#/$defs/atRoom"
              }
            ]
          }
        },
        "doors": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/door"
          }
        },
        "windows": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/window"
          }
        },
        "furniture": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/furniture"
          }
        }
      },
      "anyOf": [
        {
          "required": [
            "walls"
          ]
        },
        {
          "required": [
            "rooms"
          ]
        }
      ]
    },
    "floorplannerPlan": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "format",
        "formatVersion",
        "name",
        "document",
        "view"
      ],
      "properties": {
        "format": {
          "const": "floorplanner.plan"
        },
        "formatVersion": {
          "const": 1
        },
        "name": {
          "type": "string",
          "minLength": 1
        },
        "document": {
          "$ref": "#/$defs/document"
        },
        "view": {
          "$ref": "#/$defs/view"
        }
      }
    },
    "document": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "version",
        "walls",
        "rooms",
        "furniture"
      ],
      "properties": {
        "version": {
          "const": 1
        },
        "displayUnits": {
          "enum": [
            "metric",
            "imperial"
          ]
        },
        "ceilingHeightMm": {
          "type": "number",
          "minimum": 1800,
          "maximum": 6000
        },
        "planImageOpacity": {
          "type": "number",
          "minimum": 0,
          "maximum": 100
        },
        "planImageHidden": {
          "type": "boolean"
        },
        "calibrateMode": {
          "enum": [
            "length",
            "area"
          ]
        },
        "background": {
          "oneOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/$defs/background"
            }
          ]
        },
        "walls": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/storedWall"
          }
        },
        "rooms": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/storedRoom"
          }
        },
        "furniture": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/storedFurniture"
          }
        },
        "openings": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/storedOpening"
          }
        },
        "stairs": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/storedStair"
          }
        }
      }
    },
    "background": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "src",
        "naturalWidthPx",
        "naturalHeightPx",
        "mmPerPx",
        "origin",
        "calibrated"
      ],
      "properties": {
        "id": {
          "type": "string"
        },
        "name": {
          "type": "string"
        },
        "src": {
          "type": "string",
          "minLength": 1
        },
        "naturalWidthPx": {
          "type": "number",
          "exclusiveMinimum": 0
        },
        "naturalHeightPx": {
          "type": "number",
          "exclusiveMinimum": 0
        },
        "mmPerPx": {
          "type": "number",
          "exclusiveMinimum": 0
        },
        "origin": {
          "$ref": "#/$defs/storedPoint"
        },
        "rotationDeg": {
          "type": "number"
        },
        "calibrated": {
          "type": "boolean"
        }
      }
    },
    "storedWall": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "a",
        "b",
        "thicknessMm"
      ],
      "properties": {
        "id": {
          "type": "string",
          "minLength": 1
        },
        "a": {
          "$ref": "#/$defs/storedPoint"
        },
        "b": {
          "$ref": "#/$defs/storedPoint"
        },
        "thicknessMm": {
          "type": "number",
          "exclusiveMinimum": 0
        }
      }
    },
    "storedRoom": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "polygon",
        "label"
      ],
      "properties": {
        "id": {
          "type": "string",
          "minLength": 1
        },
        "label": {
          "type": "string"
        },
        "polygon": {
          "type": "array",
          "minItems": 3,
          "items": {
            "$ref": "#/$defs/storedPoint"
          }
        },
        "labelOffset": {
          "$ref": "#/$defs/storedPoint"
        }
      }
    },
    "storedFurniture": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "kind",
        "position",
        "rotationDeg",
        "widthMm",
        "heightMm"
      ],
      "properties": {
        "id": {
          "type": "string",
          "minLength": 1
        },
        "kind": {
          "type": "string"
        },
        "position": {
          "$ref": "#/$defs/storedPoint"
        },
        "rotationDeg": {
          "type": "number"
        },
        "widthMm": {
          "type": "number",
          "exclusiveMinimum": 0
        },
        "heightMm": {
          "type": "number",
          "exclusiveMinimum": 0
        },
        "verticalHeightMm": {
          "type": "number",
          "exclusiveMinimum": 0
        },
        "presetKey": {
          "enum": [
            "bed",
            "sofa",
            "armchair",
            "dining-table",
            "dining-chair",
            "coffee-table",
            "desk",
            "wardrobe",
            "fridge",
            "toilet",
            "bath",
            "basin",
            "tv-wall",
            "tv-stand",
            "tv-unit",
            "bookcase",
            "sideboard",
            "sofa-2",
            "ottoman",
            "rug",
            "floor-lamp",
            "plant",
            "fridge-freezer",
            "dishwasher",
            "washing-machine",
            "tumble-dryer",
            "range-cooker",
            "kitchen-island",
            "bar-stool",
            "chest-of-drawers",
            "bedside-table",
            "cot-bed",
            "desk-chair",
            "filing-cabinet",
            "radiator",
            "shower-tray",
            "upright-piano",
            "garden-table"
          ]
        }
      }
    },
    "storedOpening": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "kind",
        "wallId",
        "centerAlongMm",
        "widthMm",
        "heightMm"
      ],
      "properties": {
        "id": {
          "type": "string",
          "minLength": 1
        },
        "kind": {
          "enum": [
            "door",
            "window"
          ]
        },
        "wallId": {
          "type": "string",
          "minLength": 1
        },
        "centerAlongMm": {
          "type": "number"
        },
        "widthMm": {
          "type": "number",
          "exclusiveMinimum": 0
        },
        "heightMm": {
          "type": "number",
          "exclusiveMinimum": 0
        },
        "sillHeightMm": {
          "type": "number",
          "minimum": 0
        },
        "hinge": {
          "enum": [
            "left",
            "right"
          ]
        },
        "swing": {
          "enum": [
            "in",
            "out"
          ]
        },
        "doorType": {
          "enum": [
            "single",
            "double",
            "sliding"
          ]
        },
        "windowType": {
          "enum": [
            "standard",
            "bay"
          ]
        },
        "bayDepthMm": {
          "type": "number",
          "exclusiveMinimum": 0
        },
        "bayAngleDeg": {
          "enum": [
            45,
            90
          ]
        },
        "baySide": {
          "enum": [
            "in",
            "out"
          ]
        }
      }
    },
    "storedStair": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "position",
        "widthMm",
        "steps",
        "heightMm",
        "shape"
      ],
      "properties": {
        "id": {
          "type": "string",
          "minLength": 1
        },
        "position": {
          "$ref": "#/$defs/storedPoint"
        },
        "rotationDeg": {
          "type": "number"
        },
        "widthMm": {
          "type": "number",
          "exclusiveMinimum": 0
        },
        "steps": {
          "type": "integer",
          "minimum": 2
        },
        "heightMm": {
          "type": "number",
          "exclusiveMinimum": 0
        },
        "shape": {
          "enum": [
            "straight",
            "l",
            "u"
          ]
        },
        "turn": {
          "enum": [
            "left",
            "right"
          ]
        },
        "flipped": {
          "type": "boolean"
        }
      }
    },
    "view": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "zoom",
        "panX",
        "panY",
        "mode"
      ],
      "properties": {
        "zoom": {
          "type": "number",
          "exclusiveMinimum": 0
        },
        "panX": {
          "type": "number"
        },
        "panY": {
          "type": "number"
        },
        "mode": {
          "enum": [
            "2d",
            "3d"
          ]
        }
      }
    }
  },
  "oneOf": [
    {
      "$ref": "#/$defs/agentPlan"
    },
    {
      "$ref": "#/$defs/floorplannerPlan"
    }
  ]
}
