{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://aurora.goatsoft.io/schema/v1.json",
  "title": "Aurora background",
  "description": "An animated background for @goatsoft/aurora. Declarative: it never contains code.",
  "type": "object",
  "properties": {
    "$schema": {
      "type": "string",
      "description": "JSON Schema URL, for editor autocomplete."
    },
    "format": {
      "const": "aurora",
      "description": "Always \"aurora\"."
    },
    "version": {
      "const": 1,
      "description": "Format version. Older files are migrated forward on load."
    },
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 120,
      "description": "Display name, shown in Studio and preset galleries."
    },
    "canvas": {
      "type": "object",
      "properties": {
        "fade": {
          "enum": [
            "none",
            "x",
            "y"
          ],
          "type": "string",
          "description": "Edge fade: \"y\" fades top and bottom, \"x\" left and right.",
          "default": "none"
        },
        "fixed": {
          "type": "boolean",
          "description": "Pin the background to the viewport instead of scrolling with its element.",
          "default": false
        },
        "parallax": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Scroll parallax: 0 scrolls with the page, 1 stays fixed.",
          "default": 0
        }
      },
      "required": [],
      "additionalProperties": false,
      "default": {}
    },
    "motion": {
      "type": "object",
      "properties": {
        "speed": {
          "type": "number",
          "minimum": 0,
          "maximum": 10,
          "description": "Global time multiplier. 0 freezes the background.",
          "default": 1
        },
        "reduced": {
          "enum": [
            "still",
            "slow",
            "css"
          ],
          "type": "string",
          "description": "Behaviour under prefers-reduced-motion: \"still\" renders one frame, \"slow\" runs at a tenth of the speed, \"css\" uses the CSS fallback.",
          "default": "still"
        }
      },
      "required": [],
      "additionalProperties": false,
      "default": {}
    },
    "palette": {
      "type": "array",
      "items": {
        "type": "string",
        "description": "A colour: oklch(L C H), oklab(L a b), color(srgb|display-p3 r g b) or #hex. OKLCH is preferred.",
        "examples": [
          "oklch(0.68 0.16 245)",
          "oklch(0.56 0.22 285 / 0.8)",
          "#4f8cff"
        ],
        "pattern": "^\\s*(#|oklch\\(|oklab\\(|color\\()"
      },
      "minItems": 1,
      "maxItems": 16,
      "description": "Colours referenced by layers, by index."
    },
    "layers": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "pattern": "^[a-z][a-z\\d]*(?:-[a-z\\d]+)*$",
            "description": "Generator id, for example \"aurora-fbm\", \"mesh\" or \"grain\"."
          },
          "blend": {
            "enum": [
              "normal",
              "screen",
              "add",
              "multiply",
              "overlay"
            ],
            "type": "string",
            "description": "How this layer composites onto the layers below it.",
            "default": "normal"
          },
          "opacity": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Layer opacity.",
            "default": 1
          },
          "params": {
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {
              "anyOf": [
                {
                  "type": "number"
                },
                {
                  "type": "boolean"
                },
                {
                  "type": "string"
                }
              ]
            },
            "description": "Generator parameters. Each generator defines its own names, ranges and defaults.",
            "default": {}
          },
          "colors": {
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Indices into the palette, in the order the generator uses them.",
            "default": []
          },
          "mix": {
            "enum": [
              "oklab",
              "srgb"
            ],
            "type": "string",
            "description": "Colour space for blending this layer's colours. \"srgb\" exists for bit-exact parity with the classic presets.",
            "default": "oklab"
          },
          "mask": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "type": {
                    "const": "linear"
                  },
                  "angle": {
                    "type": "number",
                    "description": "Direction in degrees, CSS convention (180 = top to bottom).",
                    "default": 180
                  },
                  "start": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1,
                    "description": "Where the fade starts along the direction (fully opaque before it).",
                    "default": 0
                  },
                  "end": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1,
                    "description": "Where the fade ends (fully transparent after it).",
                    "default": 1
                  }
                },
                "required": [
                  "type"
                ],
                "additionalProperties": false
              },
              {
                "type": "object",
                "properties": {
                  "type": {
                    "const": "radial"
                  },
                  "x": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1,
                    "description": "Centre, as a fraction of the width.",
                    "default": 0.5
                  },
                  "y": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1,
                    "description": "Centre, as a fraction of the height.",
                    "default": 0.5
                  },
                  "start": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1,
                    "description": "Radius where the fade starts, as a fraction of the half-diagonal.",
                    "default": 0
                  },
                  "end": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1,
                    "description": "Radius where the fade ends.",
                    "default": 1
                  }
                },
                "required": [
                  "type"
                ],
                "additionalProperties": false
              }
            ],
            "description": "Fades the layer out with a linear or radial ramp."
          }
        },
        "required": [
          "type"
        ],
        "additionalProperties": false
      },
      "minItems": 1,
      "maxItems": 16,
      "description": "Layer stack, bottom first."
    },
    "fallback": {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "mode": {
              "const": "auto"
            }
          },
          "required": [
            "mode"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "mode": {
              "const": "css"
            },
            "layers": {
              "type": "array",
              "items": {
                "type": "string",
                "minLength": 1,
                "pattern": "^[^;{}<>@\\\\]*$",
                "description": "A CSS <image>, typically a gradient: radial-gradient(in oklab, …)."
              },
              "minItems": 1
            }
          },
          "required": [
            "mode",
            "layers"
          ],
          "additionalProperties": false
        }
      ],
      "description": "CSS shown without WebGPU: \"auto\" compiles it from the layers, \"css\" uses hand-tuned gradients.",
      "default": {
        "mode": "auto"
      }
    }
  },
  "required": [
    "format",
    "version",
    "name",
    "palette",
    "layers"
  ],
  "additionalProperties": false
}
