{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Flipline Xsheet Project",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "format",
    "version",
    "name",
    "fps",
    "source",
    "cells"
  ],
  "properties": {
    "format": {
      "const": "flipline-xsheet"
    },
    "version": {
      "const": 1
    },
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 120
    },
    "fps": {
      "type": "integer",
      "minimum": 1,
      "maximum": 30
    },
    "source": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "format",
        "version",
        "name",
        "width",
        "height",
        "fps",
        "background",
        "transparent",
        "frames",
        "layers"
      ],
      "properties": {
        "format": {
          "const": "flipline"
        },
        "version": {
          "const": 1
        },
        "name": {
          "type": "string",
          "maxLength": 120
        },
        "width": {
          "type": "integer",
          "minimum": 32,
          "maximum": 1600
        },
        "height": {
          "type": "integer",
          "minimum": 32,
          "maximum": 1600
        },
        "fps": {
          "type": "integer",
          "minimum": 1,
          "maximum": 30
        },
        "background": {
          "type": "string",
          "pattern": "^#[a-fA-F0-9]{6}$"
        },
        "transparent": {
          "type": "boolean"
        },
        "paper": {
          "enum": [
            "plain",
            "grain",
            "linen"
          ]
        },
        "frames": {
          "type": "array",
          "minItems": 1,
          "maxItems": 24,
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "hold",
              "label"
            ],
            "properties": {
              "id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 80
              },
              "hold": {
                "type": "integer",
                "minimum": 1,
                "maximum": 10
              },
              "label": {
                "type": "string",
                "maxLength": 80
              }
            }
          }
        },
        "layers": {
          "type": "array",
          "minItems": 1,
          "maxItems": 4,
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "visible",
              "locked",
              "opacity",
              "cels"
            ],
            "properties": {
              "id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 80
              },
              "name": {
                "type": "string",
                "maxLength": 80
              },
              "visible": {
                "type": "boolean"
              },
              "locked": {
                "type": "boolean"
              },
              "opacity": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              },
              "cels": {
                "type": "array",
                "minItems": 1,
                "maxItems": 24,
                "items": {
                  "type": "array",
                  "maxItems": 500,
                  "items": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "id",
                      "kind",
                      "points",
                      "color",
                      "size",
                      "fill"
                    ],
                    "properties": {
                      "brush": {
                        "type": "object",
                        "additionalProperties": false,
                        "required": [
                          "kind",
                          "opacity",
                          "flow",
                          "spacing",
                          "texture",
                          "pressure",
                          "seed"
                        ],
                        "properties": {
                          "kind": {
                            "enum": [
                              "ink",
                              "pencil",
                              "marker",
                              "wash",
                              "airbrush"
                            ]
                          },
                          "opacity": {
                            "type": "number",
                            "minimum": 0,
                            "maximum": 1
                          },
                          "flow": {
                            "type": "number",
                            "minimum": 0,
                            "maximum": 1
                          },
                          "spacing": {
                            "type": "number",
                            "minimum": 0.08,
                            "maximum": 1
                          },
                          "texture": {
                            "type": "number",
                            "minimum": 0,
                            "maximum": 1
                          },
                          "pressure": {
                            "type": "boolean"
                          },
                          "seed": {
                            "type": "integer",
                            "minimum": 0,
                            "maximum": 4294967295
                          }
                        }
                      },
                      "pressures": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 4096,
                        "items": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 1
                        }
                      },
                      "id": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 80
                      },
                      "kind": {
                        "enum": [
                          "pen",
                          "eraser",
                          "line",
                          "rect",
                          "ellipse",
                          "image"
                        ]
                      },
                      "points": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 4096,
                        "items": {
                          "type": "array",
                          "minItems": 2,
                          "maxItems": 2,
                          "items": {
                            "type": "number",
                            "minimum": 0,
                            "maximum": 1
                          }
                        }
                      },
                      "color": {
                        "type": "string",
                        "pattern": "^#[a-fA-F0-9]{6}$"
                      },
                      "size": {
                        "type": "number",
                        "minimum": 1,
                        "maximum": 100
                      },
                      "fill": {
                        "type": "boolean"
                      },
                      "source": {
                        "type": "string",
                        "pattern": "^data:image/(png|jpeg|webp);base64,[A-Za-z0-9+/=]+$"
                      },
                      "angle": {
                        "type": "number",
                        "minimum": -360,
                        "maximum": 360,
                        "description": "Clockwise rotation in degrees around the center of the mark bounds (normalized to -180…180)."
                      },
                      "flipX": {
                        "type": "boolean",
                        "description": "Mirror horizontally around the mark center."
                      },
                      "flipY": {
                        "type": "boolean",
                        "description": "Mirror vertically around the mark center."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "description": "Normalized drawing coordinates. Each layer has one cel per frame. At most 2 MP canvas, 50000 points, 2000 marks and 8 million embedded source characters in total. Image/shape marks require two points; IDs are unique within their collection. Optional angle/flipX/flipY transform a mark around the center of its point bounds."
    },
    "cells": {
      "type": "array",
      "minItems": 1,
      "maxItems": 4,
      "items": {
        "type": "array",
        "minItems": 1,
        "maxItems": 240,
        "items": {
          "type": "integer",
          "minimum": 0,
          "maximum": 24
        }
      }
    }
  },
  "description": "One column per source layer, equal tick counts. Zero is blank; 1–source.frames.length references that layer’s drawing. Source holds are ignored after conversion; Xsheet cells define timing."
}
