{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "ggsvelte PortableSpec",
  "description": "A ggsvelte plot specification (schema v0 — UNSTABLE; served from the repo until schema hosting exists).",
  "$defs": {
    "CellValue": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "number"
        },
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "description": "A single data cell: string, number, boolean, or null. Dates travel as ISO 8601 strings (e.g. \"2026-07-10\"); non-finite numbers travel as null."
    },
    "DataValues": {
      "type": "object",
      "required": [
        "values"
      ],
      "properties": {
        "values": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {},
            "additionalProperties": {
              "$ref": "#/$defs/CellValue"
            },
            "description": "One data row: an object mapping field names to cell values."
          },
          "description": "Row-oriented inline data: an array of row objects sharing field names."
        }
      },
      "additionalProperties": false,
      "description": "Inline row-oriented data. Example: {\"values\": [{\"x\": 1, \"y\": 2}]}."
    },
    "DataColumns": {
      "type": "object",
      "required": [
        "columns"
      ],
      "properties": {
        "columns": {
          "type": "object",
          "additionalProperties": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/CellValue"
            }
          },
          "description": "Column-oriented inline data: an object mapping each field name to an array of cell values. All arrays must have the same length."
        }
      },
      "additionalProperties": false,
      "description": "Inline column-oriented data. Example: {\"columns\": {\"x\": [1, 2], \"y\": [3, 4]}}."
    },
    "DataName": {
      "type": "object",
      "required": [
        "name"
      ],
      "properties": {
        "name": {
          "type": "string",
          "description": "Name of a dataset provided out-of-band: either a key of the spec's top-level `datasets`, or a dataset passed by the host at render time."
        }
      },
      "additionalProperties": false,
      "description": "A reference to a named dataset. Example: {\"name\": \"cars\"}."
    },
    "DataRef": {
      "anyOf": [
        {
          "$ref": "#/$defs/DataValues"
        },
        {
          "$ref": "#/$defs/DataColumns"
        },
        {
          "$ref": "#/$defs/DataName"
        }
      ],
      "description": "Where a plot's data comes from: inline rows ({values}), inline columns ({columns}), or a named dataset ({name}). Exactly one form."
    },
    "InlineData": {
      "anyOf": [
        {
          "$ref": "#/$defs/DataValues"
        },
        {
          "$ref": "#/$defs/DataColumns"
        }
      ],
      "description": "Inline data only ({values} or {columns}); used for entries of `datasets`."
    },
    "FieldRef": {
      "type": "object",
      "required": [
        "field"
      ],
      "properties": {
        "field": {
          "type": "string",
          "description": "Name of the data column this channel reads from."
        }
      },
      "additionalProperties": false,
      "description": "Map this channel to a data field (column). Example: {\"field\": \"displ\"}. This is the canonical form — bare strings are NOT valid channel values."
    },
    "ValueRef": {
      "type": "object",
      "required": [
        "value"
      ],
      "properties": {
        "value": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "number"
            },
            {
              "type": "boolean"
            }
          ],
          "description": "The constant value applied to every mark."
        },
        "scale": {
          "type": "boolean",
          "description": "If true, the constant is passed THROUGH the channel's scale (like a data value). Default false: the constant is used literally (e.g. a CSS color)."
        }
      },
      "additionalProperties": false,
      "description": "Map this channel to a constant. Example: {\"value\": \"steelblue\"} sets a literal color; {\"value\": \"treatment\", \"scale\": true} routes the constant through the scale."
    },
    "StatRef": {
      "type": "object",
      "required": [
        "stat"
      ],
      "properties": {
        "stat": {
          "type": "string",
          "description": "Name of a stat-generated column computed after the layer's stat runs (e.g. \"count\" for the count stat). after_stat."
        }
      },
      "additionalProperties": false,
      "description": "Map this channel to a column generated by the layer's stat (after-stat form). Example: {\"stat\": \"count\"}."
    },
    "ChannelValue": {
      "anyOf": [
        {
          "$ref": "#/$defs/FieldRef"
        },
        {
          "$ref": "#/$defs/ValueRef"
        },
        {
          "$ref": "#/$defs/StatRef"
        },
        {
          "type": "null"
        }
      ],
      "description": "How one aesthetic channel gets its value: a data field ({field}), a constant ({value, scale?}), a stat output ({stat}), or null to UNSET a channel inherited from the plot-level mapping. Bare strings are not valid."
    },
    "Aes": {
      "type": "object",
      "properties": {
        "x": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Horizontal position channel."
        },
        "y": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Vertical position channel."
        },
        "color": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Stroke/point color channel. Discrete fields get a categorical palette; quantitative fields get a sequential ramp."
        },
        "fill": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Fill color channel (areas, bars, filled shapes). Discrete fields get a categorical palette; quantitative fields get a sequential ramp."
        },
        "size": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Mark size channel (AREA-scaled — sqrt scale; use `linewidth` for stroke width, which scales linearly)."
        },
        "linewidth": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Stroke width channel (LENGTH-scaled — linear; distinct from `size`, which scales by area)."
        },
        "alpha": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Opacity channel, 0 (transparent) to 1 (opaque)."
        },
        "shape": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Finite point-symbol channel. Continuous values require a binned scale."
        },
        "linetype": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Finite stroke-pattern channel. Continuous values require a binned scale."
        },
        "group": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Explicit grouping channel. Overrides the default grouping (the interaction of all discrete mapped aesthetics). A constant (e.g. {\"value\": 1}) forces a single group."
        },
        "label": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Text label channel (used by the text geom; never participates in grouping)."
        },
        "weight": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Statistical weight channel. The count, bin, and density stats sum weights instead of counting rows. Never participates in grouping."
        },
        "sample": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Sample distribution channel for Q–Q plots. The qq / qq_line stats read this column; x/y become theoretical and sample quantiles after the stat. Never participates in grouping."
        },
        "ymin": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Lower y bound (errorbar identity, rect edges, ribbon x-orientation). Quantitative values only."
        },
        "ymax": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Upper y bound (errorbar identity, rect edges, ribbon x-orientation). Quantitative values only."
        },
        "xmin": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Left edge / lower x bound (geom rect; ribbon y-orientation). Quantitative values only."
        },
        "xmax": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Right edge / upper x bound (geom rect; ribbon y-orientation). Quantitative values only."
        },
        "xend": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Segment end x (geom segment). Trains the x scale together with aes.x; may be discrete or continuous."
        },
        "yend": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Segment end y (geom segment). Trains the y scale together with aes.y; may be discrete or continuous."
        },
        "width": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Cell width for geom tile (data units after position transform; not a trained position scale). Prefer params.width for a constant."
        },
        "height": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Cell height for geom tile (data units after position transform; not a trained position scale). Prefer params.height for a constant."
        },
        "z": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Surface height for geom contour / stat contour (quantitative grid values over continuous x×y;)."
        },
        "map_id": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Region join key for geom_map (value-table column matched to the map data id column;)."
        },
        "angle": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Spoke direction in radians (geom spoke; 0 = +x, π/2 = +y). Quantitative only. May also be set as params.angle."
        },
        "radius": {
          "$ref": "#/$defs/ChannelValue",
          "description": "Spoke length in data units (geom spoke). Quantitative only. May also be set as params.radius."
        }
      },
      "additionalProperties": false,
      "description": "Aesthetic mapping: which channels read which data fields/constants. Plot-level aes is inherited by every layer; a layer's aes overrides per channel, and null unsets an inherited channel."
    },
    "ColorStop": {
      "type": "object",
      "required": [
        "offset",
        "color"
      ],
      "properties": {
        "offset": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Stop position along the gradient, between 0 and 1 inclusive."
        },
        "color": {
          "type": "string",
          "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$",
          "description": "A solid #rgb or #rrggbb color (no CSS names, url(), or filter strings)."
        },
        "opacity": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Optional stop opacity between 0 and 1 inclusive. Default 1."
        }
      },
      "additionalProperties": false,
      "description": "One ordered gradient color stop. Stops must be non-decreasing by offset (validated structurally)."
    },
    "PaintSpace": {
      "anyOf": [
        {
          "type": "string",
          "const": "mark"
        },
        {
          "type": "string",
          "const": "panel"
        },
        {
          "type": "string",
          "const": "plot"
        }
      ],
      "description": "Gradient coordinate space: \"mark\" (object bounding box, default), \"panel\" (panel-local px), or \"plot\" (plot-local px including panels)."
    },
    "LinearGradientPaint": {
      "type": "object",
      "required": [
        "type",
        "x1",
        "y1",
        "x2",
        "y2",
        "stops",
        "fallback"
      ],
      "properties": {
        "type": {
          "type": "string",
          "const": "linear"
        },
        "x1": {
          "type": "number",
          "description": "Gradient start x in the chosen space."
        },
        "y1": {
          "type": "number",
          "description": "Gradient start y in the chosen space."
        },
        "x2": {
          "type": "number",
          "description": "Gradient end x in the chosen space."
        },
        "y2": {
          "type": "number",
          "description": "Gradient end y in the chosen space."
        },
        "space": {
          "$ref": "#/$defs/PaintSpace"
        },
        "stops": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ColorStop"
          },
          "minItems": 2,
          "maxItems": 16,
          "description": "Ordered color stops (at least 2, at most 16)."
        },
        "fallback": {
          "type": "string",
          "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$",
          "description": "Required solid #rgb/#rrggbb used for a11y, forced-SVG, and reduced-effects paths."
        }
      },
      "additionalProperties": false,
      "description": "Deterministic linear gradient paint for within-mark fill or stroke. Not a data scale."
    },
    "RadialGradientPaint": {
      "type": "object",
      "required": [
        "type",
        "cx",
        "cy",
        "r",
        "stops",
        "fallback"
      ],
      "properties": {
        "type": {
          "type": "string",
          "const": "radial"
        },
        "cx": {
          "type": "number",
          "description": "Gradient center x in the chosen space."
        },
        "cy": {
          "type": "number",
          "description": "Gradient center y in the chosen space."
        },
        "r": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Gradient radius in the chosen space. Must be greater than 0."
        },
        "space": {
          "$ref": "#/$defs/PaintSpace"
        },
        "stops": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ColorStop"
          },
          "minItems": 2,
          "maxItems": 16,
          "description": "Ordered color stops (at least 2, at most 16)."
        },
        "fallback": {
          "type": "string",
          "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$",
          "description": "Required solid #rgb/#rrggbb used for a11y, forced-SVG, and reduced-effects paths."
        }
      },
      "additionalProperties": false,
      "description": "Deterministic radial gradient paint for within-mark fill or stroke. Not a data scale."
    },
    "GradientPaint": {
      "anyOf": [
        {
          "$ref": "#/$defs/LinearGradientPaint"
        },
        {
          "$ref": "#/$defs/RadialGradientPaint"
        }
      ],
      "description": "Closed portable gradient paint: linear or radial with solid fallback."
    },
    "GlowSpec": {
      "type": "object",
      "required": [
        "color",
        "radius",
        "opacity"
      ],
      "properties": {
        "color": {
          "type": "string",
          "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$",
          "description": "A solid #rgb or #rrggbb color (no CSS names, url(), or filter strings)."
        },
        "radius": {
          "type": "number",
          "exclusiveMinimum": 0,
          "maximum": 32,
          "description": "Blur radius in CSS px, greater than 0 and at most 32."
        },
        "opacity": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Glow opacity between 0 and 1 inclusive."
        }
      },
      "additionalProperties": false,
      "description": "Bounded glow treatment (explicit color, radius, opacity). Opt-in mark appearance, not theme decoration."
    },
    "PointParams": {
      "type": "object",
      "properties": {
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Point opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "size": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Point radius in px. Must be greater than 0. Default 2.5."
        },
        "shape": {
          "anyOf": [
            {
              "type": "string",
              "const": "circle"
            },
            {
              "type": "string",
              "const": "triangle"
            },
            {
              "type": "string",
              "const": "square"
            },
            {
              "type": "string",
              "const": "diamond"
            },
            {
              "type": "string",
              "const": "plus"
            },
            {
              "type": "string",
              "const": "cross"
            }
          ],
          "description": "Point shape. One of \"circle\", \"triangle\", \"square\", \"diamond\", \"plus\", \"cross\". Default \"circle\"."
        },
        "bins": {
          "type": "integer",
          "minimum": 1,
          "description": "STAT SUMMARY_BIN ONLY: number of bins (integer ≥ 1). Default 30 — advisory. Overridden by binwidth."
        },
        "binwidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "STAT SUMMARY_BIN ONLY: bin width in data units (must be greater than 0). Takes precedence over bins."
        },
        "boundary": {
          "type": "number",
          "description": "STAT SUMMARY_BIN ONLY: align a bin EDGE with this x value. Mutually exclusive with center."
        },
        "center": {
          "type": "number",
          "description": "STAT SUMMARY_BIN ONLY: align a bin CENTER with this x value. Mutually exclusive with boundary."
        },
        "closed": {
          "anyOf": [
            {
              "type": "string",
              "const": "right"
            },
            {
              "type": "string",
              "const": "left"
            }
          ],
          "description": "STAT SUMMARY_BIN ONLY: which edge of each bin is inclusive: \"right\" (default) or \"left\"."
        },
        "fun": {
          "anyOf": [
            {
              "type": "string",
              "const": "first"
            },
            {
              "type": "string",
              "const": "last"
            },
            {
              "type": "string",
              "const": "mean"
            },
            {
              "type": "string",
              "const": "median"
            },
            {
              "type": "string",
              "const": "min"
            },
            {
              "type": "string",
              "const": "max"
            },
            {
              "type": "string",
              "const": "sum"
            }
          ],
          "description": "SUMMARY_BIN center fun (mean/median/sum;) or MANUAL named transform (first|last|mean|median|min|max|sum;). Required when stat is \"manual\"."
        },
        "funMin": {
          "$ref": "#/$defs/SummaryFun",
          "description": "STAT SUMMARY_BIN ONLY: lower bound summary (ymin)."
        },
        "funMax": {
          "$ref": "#/$defs/SummaryFun",
          "description": "STAT SUMMARY_BIN ONLY: upper bound summary (ymax)."
        }
      },
      "additionalProperties": false,
      "description": "Styling parameters for the point geom, plus summary_bin and/or manual controls."
    },
    "LineParams": {
      "type": "object",
      "properties": {
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Line opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Stroke width in px. Must be greater than 0. Default 1.5."
        },
        "curve": {
          "anyOf": [
            {
              "type": "string",
              "const": "linear"
            },
            {
              "type": "string",
              "const": "step"
            },
            {
              "type": "string",
              "const": "step-hv"
            },
            {
              "type": "string",
              "const": "step-vh"
            }
          ],
          "description": "Interpolation: \"linear\" (default), \"step\" (mid-x corners), \"step-hv\" (horizontal then vertical — correct for ECDF), or \"step-vh\"."
        },
        "pad": {
          "type": "boolean",
          "description": "With stat ecdf: when true (default), prepend (xmin, 0) so step stairs start at zero. Finite-clamped."
        },
        "n": {
          "type": "integer",
          "minimum": 1,
          "description": "With stat ecdf: evaluate on n equally spaced x in [min, max] per group; omit for one point per unique x."
        },
        "connection": {
          "anyOf": [
            {
              "type": "string",
              "const": "hv",
              "description": "STAT CONNECT: horizontal then vertical (default)."
            },
            {
              "type": "string",
              "const": "vh",
              "description": "STAT CONNECT: vertical then horizontal."
            },
            {
              "type": "string",
              "const": "mid",
              "description": "STAT CONNECT: step at the midpoint between adjacent x values."
            },
            {
              "type": "string",
              "const": "linear",
              "description": "STAT CONNECT: straight segment (identity vertices)."
            }
          ],
          "description": "STAT CONNECT ONLY: how successive points join — \"hv\" (default), \"vh\", \"mid\", or \"linear\". Ignored for other stats."
        },
        "bins": {
          "type": "integer",
          "minimum": 1,
          "description": "STAT BIN / SUMMARY_BIN: number of bins (integer ≥ 1). Default 30 — an advisory reminds you to pick a real value. Overridden by binwidth."
        },
        "binwidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "STAT BIN / SUMMARY_BIN: bin width in data units (must be greater than 0). Takes precedence over bins."
        },
        "boundary": {
          "type": "number",
          "description": "STAT BIN / SUMMARY_BIN: align a bin EDGE with this x value. Mutually exclusive with center."
        },
        "center": {
          "type": "number",
          "description": "STAT BIN / SUMMARY_BIN: align a bin CENTER with this x value. Mutually exclusive with boundary."
        },
        "closed": {
          "anyOf": [
            {
              "type": "string",
              "const": "right"
            },
            {
              "type": "string",
              "const": "left"
            }
          ],
          "description": "STAT BIN / SUMMARY_BIN: which edge of each bin is inclusive: \"right\" (default) or \"left\"."
        },
        "fun": {
          "anyOf": [
            {
              "type": "string",
              "const": "first"
            },
            {
              "type": "string",
              "const": "last"
            },
            {
              "type": "string",
              "const": "mean"
            },
            {
              "type": "string",
              "const": "median"
            },
            {
              "type": "string",
              "const": "min"
            },
            {
              "type": "string",
              "const": "max"
            },
            {
              "type": "string",
              "const": "sum"
            }
          ],
          "description": "SUMMARY_BIN center fun (mean/median/sum;) or MANUAL named transform (first|last|mean|median|min|max|sum;). Required when stat is \"manual\"."
        },
        "funMin": {
          "$ref": "#/$defs/SummaryFun",
          "description": "STAT SUMMARY_BIN ONLY: lower bound summary (ymin)."
        },
        "funMax": {
          "$ref": "#/$defs/SummaryFun",
          "description": "STAT SUMMARY_BIN ONLY: upper bound summary (ymax)."
        },
        "strokePaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient stroke paint (not a data scale). Requires a solid fallback."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Styling parameters for the line geom, plus optional stat-bin (freqpoly), summary_bin, manual, or ecdf pad/n controls."
    },
    "StepParams": {
      "type": "object",
      "properties": {
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Step-line opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Stroke width in px. Must be greater than 0. Default 1.5."
        },
        "direction": {
          "anyOf": [
            {
              "type": "string",
              "const": "hv"
            },
            {
              "type": "string",
              "const": "vh"
            },
            {
              "type": "string",
              "const": "mid"
            }
          ],
          "description": "Step corner placement: \"hv\" horizontal then vertical (default), \"vh\" vertical then horizontal, \"mid\" change at the midpoint between x positions."
        },
        "strokePaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient stroke paint (not a data scale). Requires a solid fallback."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Styling parameters for the step geom."
    },
    "PathParams": {
      "type": "object",
      "properties": {
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Path opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Stroke width in px. Must be greater than 0. Default 1.5."
        },
        "curve": {
          "anyOf": [
            {
              "type": "string",
              "const": "linear"
            },
            {
              "type": "string",
              "const": "step"
            }
          ],
          "description": "Interpolation between points: \"linear\" (straight segments, default) or \"step\" (horizontal-then-vertical steps)."
        },
        "connection": {
          "anyOf": [
            {
              "type": "string",
              "const": "hv",
              "description": "STAT CONNECT: horizontal then vertical (default)."
            },
            {
              "type": "string",
              "const": "vh",
              "description": "STAT CONNECT: vertical then horizontal."
            },
            {
              "type": "string",
              "const": "mid",
              "description": "STAT CONNECT: step at the midpoint between adjacent x values."
            },
            {
              "type": "string",
              "const": "linear",
              "description": "STAT CONNECT: straight segment (identity vertices)."
            }
          ],
          "description": "STAT CONNECT ONLY: how successive points join — \"hv\" (default), \"vh\", \"mid\", or \"linear\". Ignored for other stats."
        },
        "fun": {
          "anyOf": [
            {
              "type": "string",
              "const": "first"
            },
            {
              "type": "string",
              "const": "last"
            },
            {
              "type": "string",
              "const": "mean"
            },
            {
              "type": "string",
              "const": "median"
            },
            {
              "type": "string",
              "const": "min"
            },
            {
              "type": "string",
              "const": "max"
            },
            {
              "type": "string",
              "const": "sum"
            }
          ],
          "description": "STAT MANUAL ONLY: portable named transform (first|last|mean|median|min|max|sum). Required when stat is \"manual\"."
        },
        "level": {
          "type": "number",
          "exclusiveMinimum": 0,
          "exclusiveMaximum": 1,
          "description": "STAT ELLIPSE ONLY: confidence level of the bivariate normal ellipse, strictly between 0 and 1. Default 0.95."
        },
        "type": {
          "type": "string",
          "const": "norm",
          "description": "STAT ELLIPSE ONLY: construction type. Only \"norm\" (bivariate normal) is supported in v1."
        },
        "segments": {
          "type": "integer",
          "minimum": 3,
          "maximum": 500,
          "description": "STAT ELLIPSE ONLY: number of perimeter samples before the closing duplicate (output length = segments + 1). Default 51."
        },
        "strokePaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient stroke paint (not a data scale). Requires a solid fallback."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Styling parameters for the path geom (data-order polylines), plus optional connect/manual/ellipse controls."
    },
    "ColParams": {
      "type": "object",
      "properties": {
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Bar opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "width": {
          "type": "number",
          "exclusiveMinimum": 0,
          "maximum": 1,
          "description": "Bar width as a fraction of the band step. Must be greater than 0 and at most 1. Default 0.9."
        },
        "fillPaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient fill paint (not a data scale). Requires a solid fallback."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Styling parameters for the col geom."
    },
    "BarParams": {
      "type": "object",
      "properties": {
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Bar opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "width": {
          "type": "number",
          "exclusiveMinimum": 0,
          "maximum": 1,
          "description": "Bar width as a fraction of the band step (count-stat bars only; binned bars span their bin). Must be greater than 0 and at most 1. Default 0.9."
        },
        "bins": {
          "type": "integer",
          "minimum": 1,
          "description": "STAT BIN ONLY: number of bins (an integer of at least 1). Default 30 — an advisory reminds you to pick a real value. Overridden by binwidth."
        },
        "binwidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "STAT BIN ONLY: bin width in data units (must be greater than 0). Takes precedence over bins. Usually the better knob: pick a width meaningful for the data."
        },
        "boundary": {
          "type": "number",
          "description": "STAT BIN ONLY: align a bin EDGE with this x value (e.g. 0 puts bin edges at multiples of the width). Mutually exclusive with center."
        },
        "center": {
          "type": "number",
          "description": "STAT BIN ONLY: align a bin CENTER with this x value. Mutually exclusive with boundary."
        },
        "closed": {
          "anyOf": [
            {
              "type": "string",
              "const": "right"
            },
            {
              "type": "string",
              "const": "left"
            }
          ],
          "description": "STAT BIN ONLY: which edge of each bin is inclusive: \"right\" (default, matches) or \"left\"."
        },
        "fillPaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient fill paint (not a data scale). Requires a solid fallback."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for the bar and histogram geoms: styling (alpha, width) plus stat-bin binning controls (bins, binwidth, boundary, center, closed)."
    },
    "SmoothParams": {
      "type": "object",
      "properties": {
        "method": {
          "anyOf": [
            {
              "type": "string",
              "const": "lm"
            },
            {
              "type": "string",
              "const": "loess"
            }
          ],
          "description": "Smoothing method: \"lm\" (least-squares line) or \"loess\" (local polynomial regression). Omit to infer: loess for fewer than 1000 rows, lm above (an advisory reports the choice)."
        },
        "se": {
          "type": "boolean",
          "description": "Draw the confidence-interval ribbon around the fit. Default true."
        },
        "level": {
          "type": "number",
          "exclusiveMinimum": 0,
          "exclusiveMaximum": 1,
          "description": "Confidence level of the ribbon, strictly between 0 and 1. Default 0.95."
        },
        "span": {
          "type": "number",
          "exclusiveMinimum": 0,
          "maximum": 1,
          "description": "LOESS ONLY: fraction of points in each local neighborhood, greater than 0 and at most 1. Default 0.75. Smaller = wigglier."
        },
        "degree": {
          "anyOf": [
            {
              "type": "number",
              "const": 1
            },
            {
              "type": "number",
              "const": 2
            }
          ],
          "description": "LOESS ONLY: degree of the local polynomial, 1 or 2. Default 2 (the R default)."
        },
        "n": {
          "type": "integer",
          "minimum": 2,
          "maximum": 5000,
          "description": "Number of evaluation points along x (an integer between 2 and 5000). Default 80."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Stroke width of the fitted line in px. Must be greater than 0. Default 1."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Line opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "strokePaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient stroke paint for the fitted line (not a data scale)."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for the smooth geom (fitted trend line + optional se ribbon)."
    },
    "QuantileParams": {
      "type": "object",
      "properties": {
        "quantiles": {
          "type": "array",
          "items": {
            "type": "number",
            "exclusiveMinimum": 0,
            "exclusiveMaximum": 1,
            "description": "One conditional quantile τ strictly between 0 and 1."
          },
          "minItems": 1,
          "description": "Conditional quantiles of y to fit and draw. Each entry must be in (0, 1). Default [0.25, 0.5, 0.75]."
        },
        "n": {
          "type": "integer",
          "minimum": 2,
          "maximum": 5000,
          "description": "Number of evaluation points along x (integer 2–5000). Default 80. Linear fits need only endpoints; denser grids help nonlinear coords."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Stroke width of quantile lines in px. Must be greater than 0. Default 1."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Line opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "strokePaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient stroke paint for quantile lines (not a data scale)."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for the quantile geom (linear y~x quantile regression lines;). method rqss is intentionally omitted in v1."
    },
    "QqParams": {
      "type": "object",
      "properties": {
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Point opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "size": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Point size in px. Must be greater than 0."
        },
        "shape": {
          "anyOf": [
            {
              "type": "string",
              "const": "circle"
            },
            {
              "type": "string",
              "const": "triangle"
            },
            {
              "type": "string",
              "const": "square"
            },
            {
              "type": "string",
              "const": "diamond"
            },
            {
              "type": "string",
              "const": "plus"
            },
            {
              "type": "string",
              "const": "cross"
            }
          ],
          "description": "Point shape. One of \"circle\", \"triangle\", \"square\", \"diamond\", \"plus\", \"cross\". Default \"circle\"."
        }
      },
      "additionalProperties": false,
      "description": "Styling for geom_qq (Q–Q scatter). Requires aes.sample; x/y become theoretical and sample quantiles."
    },
    "QqLineParams": {
      "type": "object",
      "properties": {
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Line opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Stroke width in px. Must be greater than 0. Default 1."
        }
      },
      "additionalProperties": false,
      "description": "Styling for geom_qq_line (reference line through sample/theoretical quartile match)."
    },
    "ContourParams": {
      "type": "object",
      "properties": {
        "bins": {
          "type": "integer",
          "minimum": 1,
          "description": "Number of evenly spaced contour levels from min(z) to max(z) inclusive (integer ≥ 1). Default 10. Overridden by breaks or binwidth."
        },
        "binwidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Contour level step in z units (must be greater than 0). Takes precedence over bins; overridden by breaks."
        },
        "breaks": {
          "type": "array",
          "items": {
            "type": "number"
          },
          "minItems": 1,
          "description": "Explicit contour levels (finite numbers). Overrides bins and binwidth when non-empty."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Stroke width of contour lines in px. Must be greater than 0. Default 1."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Line opacity. Must be between 0 and 1 (inclusive). Default 1."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for geom_contour isolines. v1: regular grid only; contour_filled deferred."
    },
    "ViolinParams": {
      "type": "object",
      "properties": {
        "bw": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Kernel bandwidth in data units (must be greater than 0). Omit for R's bw.nrd0 rule-of-thumb default."
        },
        "adjust": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Bandwidth multiplier (must be greater than 0). Default 1."
        },
        "n": {
          "type": "integer",
          "minimum": 2,
          "maximum": 4096,
          "description": "Number of density grid points (2–4096). Default 512."
        },
        "trim": {
          "type": "boolean",
          "description": "When true (default), trim the density to the data range; when false, extend cut·bw tails like density()."
        },
        "scale": {
          "anyOf": [
            {
              "type": "string",
              "const": "area"
            },
            {
              "type": "string",
              "const": "count"
            },
            {
              "type": "string",
              "const": "width"
            }
          ],
          "description": "Relative violin max-width scaling: \"area\" (default), \"count\", or \"width\" (equal max width)."
        },
        "width": {
          "type": "number",
          "exclusiveMinimum": 0,
          "maximum": 1,
          "description": "Max violin width as a fraction of the discrete x band (like boxplot). Default 0.75."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Fill opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Outline stroke width in px. Must be greater than 0. Default 0.5."
        },
        "fillPaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient fill paint (not a data scale). Requires a solid fallback."
        },
        "strokePaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient stroke paint (not a data scale). Requires a solid fallback."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for the violin geom (mirrored y-density polygons)."
    },
    "BoxplotParams": {
      "type": "object",
      "properties": {
        "width": {
          "type": "number",
          "exclusiveMinimum": 0,
          "maximum": 1,
          "description": "Box width as a fraction of the band step. Must be greater than 0 and at most 1. Default 0.75. When omitted, width is also capped at 15% of the panel so few categories do not read as slabs."
        },
        "coef": {
          "type": "number",
          "minimum": 0,
          "description": "Whisker length as a multiple of the IQR (values beyond it are outliers). Must be at least 0. Default 1.5."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Stroke width of the box, whiskers, and median line in px (the median draws at twice this). Must be greater than 0. Default 1."
        },
        "outlierSize": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Outlier point radius in px. Must be greater than 0. Default 1.5."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Layer opacity. Must be between 0 and 1 (inclusive). Default 1."
        }
      },
      "additionalProperties": false,
      "description": "Styling parameters for the boxplot geom."
    },
    "FunctionRegistryName": {
      "anyOf": [
        {
          "type": "string",
          "const": "identity"
        },
        {
          "type": "string",
          "const": "dnorm"
        },
        {
          "type": "string",
          "const": "pnorm"
        },
        {
          "type": "string",
          "const": "linear"
        }
      ],
      "description": "Portable named function for stat/geom function: \"identity\", \"dnorm\" (normal PDF), \"pnorm\" (normal CDF), or \"linear\" (a + b·x)."
    },
    "FunctionArgs": {
      "type": "object",
      "properties": {
        "mean": {
          "type": "number",
          "description": "Mean for dnorm/pnorm. Default 0."
        },
        "sd": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Standard deviation for dnorm/pnorm (must be > 0). Default 1."
        },
        "a": {
          "type": "number",
          "description": "Intercept for linear (y = a + b·x). Default 0."
        },
        "b": {
          "type": "number",
          "description": "Slope for linear (y = a + b·x). Default 1."
        }
      },
      "additionalProperties": false,
      "description": "Named arguments for the registry function."
    },
    "FunctionParams": {
      "type": "object",
      "required": [
        "fun"
      ],
      "properties": {
        "fun": {
          "$ref": "#/$defs/FunctionRegistryName",
          "description": "Required named function from the portable registry."
        },
        "n": {
          "type": "integer",
          "minimum": 2,
          "maximum": 10000,
          "description": "Number of evaluation grid points (2–10000). Default 101."
        },
        "xlim": {
          "type": "array",
          "items": {
            "type": "number"
          },
          "minItems": 2,
          "maxItems": 2,
          "description": "Evaluation domain [min, max] (min < max). When omitted, uses continuous aes.x extent or peer-layer x domain."
        },
        "args": {
          "$ref": "#/$defs/FunctionArgs",
          "description": "Optional named arguments for the registry function (e.g. mean and sd for dnorm). Keys and values must be portable JSON."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Path opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Stroke width in px. Must be greater than 0. Default 1.5."
        },
        "strokePaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient stroke paint (not a data scale). Requires a solid fallback."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for geom/stat function: named fun, grid size n, optional xlim and args."
    },
    "DotplotParams": {
      "type": "object",
      "properties": {
        "bins": {
          "type": "integer",
          "minimum": 1,
          "description": "Number of bins (integer ≥ 1). Default 30 — advisory when neither bins nor binwidth is set. Overridden by binwidth."
        },
        "binwidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Histodot bin width in data units (must be greater than 0). Takes precedence over bins. Also drives default point diameter via the x scale."
        },
        "boundary": {
          "type": "number",
          "description": "Align a bin edge to this value (mutually exclusive with center)."
        },
        "center": {
          "type": "number",
          "description": "Align a bin center to this value (mutually exclusive with boundary)."
        },
        "closed": {
          "anyOf": [
            {
              "type": "string",
              "const": "right"
            },
            {
              "type": "string",
              "const": "left"
            }
          ],
          "description": "Which side of each bin is closed: \"right\" (default, (lo, hi]) or \"left\" ([lo, hi))."
        },
        "stackdir": {
          "anyOf": [
            {
              "type": "string",
              "const": "up"
            },
            {
              "type": "string",
              "const": "down"
            },
            {
              "type": "string",
              "const": "center"
            },
            {
              "type": "string",
              "const": "centerwhole"
            }
          ],
          "description": "Stack direction: \"up\" (default), \"down\", \"center\", or \"centerwhole\" (integer-aligned center)."
        },
        "stackratio": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Relative spacing between stacked dots (must be greater than 0). Default 1."
        },
        "dotsize": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Multiplier on diameter derived from binwidth × x-scale (must be greater than 0). Default 1. Ignored when params.size is set."
        },
        "size": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Point radius in px (must be greater than 0). When set, overrides binwidth-derived sizing."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Point opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "shape": {
          "anyOf": [
            {
              "type": "string",
              "const": "circle"
            },
            {
              "type": "string",
              "const": "triangle"
            },
            {
              "type": "string",
              "const": "square"
            },
            {
              "type": "string",
              "const": "diamond"
            },
            {
              "type": "string",
              "const": "plus"
            },
            {
              "type": "string",
              "const": "cross"
            }
          ],
          "description": "Point shape. One of \"circle\", \"triangle\", \"square\", \"diamond\", \"plus\", \"cross\". Default \"circle\"."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for geom_dotplot (histodot binning + stacked dots;). method=dotdensity and binaxis=y are not in v1."
    },
    "DensityParams": {
      "type": "object",
      "properties": {
        "bw": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Kernel bandwidth in data units (must be greater than 0). Omit for R's bw.nrd0 rule-of-thumb default."
        },
        "adjust": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Bandwidth multiplier (must be greater than 0). Default 1. 0.5 = half the default bandwidth (wigglier), 2 = double (smoother)."
        },
        "n": {
          "type": "integer",
          "minimum": 2,
          "maximum": 4096,
          "description": "Number of grid points the density is evaluated at (an integer between 2 and 4096). Default 512 (the R default)."
        },
        "cut": {
          "type": "number",
          "minimum": 0,
          "description": "The grid extends cut * bandwidth beyond the data extremes (at least 0). Default 3 (the R default)."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Area fill opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "fillPaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient fill paint (not a data scale). Requires a solid fallback."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for the density geom (gaussian kernel density estimate)."
    },
    "Density2dParams": {
      "type": "object",
      "properties": {
        "h": {
          "anyOf": [
            {
              "type": "number",
              "exclusiveMinimum": 0
            },
            {
              "type": "array",
              "items": {
                "type": "number",
                "exclusiveMinimum": 0
              },
              "minItems": 2,
              "maxItems": 2
            }
          ],
          "description": "Kernel bandwidth: one positive number for both axes, or [hx, hy]. Omit for MASS bandwidth.nrd per axis (then kde2d h/4 scaling)."
        },
        "adjust": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Bandwidth multiplier (must be greater than 0). Default 1."
        },
        "n": {
          "type": "integer",
          "minimum": 10,
          "maximum": 200,
          "description": "Grid resolution per axis for the KDE surface (integer 10–200). Default 100."
        },
        "bins": {
          "type": "integer",
          "minimum": 1,
          "description": "Number of contour levels of the density surface (integer ≥ 1). Default 10. Overridden by breaks."
        },
        "binwidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Contour level step in density units. Overridden by breaks."
        },
        "breaks": {
          "type": "array",
          "items": {
            "type": "number"
          },
          "minItems": 1,
          "description": "Explicit density contour levels. Overrides bins and binwidth."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Stroke width of density contours in px. Must be greater than 0. Default 1."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Line opacity. Must be between 0 and 1 (inclusive). Default 1."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for geom_density_2d / geom_density_2d_filled (bivariate KDE;). contour_var density only."
    },
    "SummaryFun": {
      "anyOf": [
        {
          "type": "string",
          "const": "mean"
        },
        {
          "type": "string",
          "const": "median"
        },
        {
          "type": "string",
          "const": "sum"
        },
        {
          "type": "string",
          "const": "min"
        },
        {
          "type": "string",
          "const": "max"
        }
      ],
      "description": "A summary function: \"mean\", \"median\", \"sum\", \"min\", or \"max\"."
    },
    "ErrorbarParams": {
      "type": "object",
      "properties": {
        "width": {
          "type": "number",
          "exclusiveMinimum": 0,
          "maximum": 1,
          "description": "Cap width as a fraction of the band step. Must be greater than 0 and at most 1. Default 0.9."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Stroke width in px. Must be greater than 0. Default 1."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Errorbar opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "fun": {
          "anyOf": [
            {
              "type": "string",
              "const": "mean"
            },
            {
              "type": "string",
              "const": "median"
            },
            {
              "type": "string",
              "const": "sum"
            }
          ],
          "description": "STAT SUMMARY ONLY: the center summary of y per x group: \"mean\" (default), \"median\", or \"sum\". With \"mean\" and no funMin/funMax, the bounds default to mean ± standard error."
        },
        "funMin": {
          "$ref": "#/$defs/SummaryFun",
          "description": "STAT SUMMARY ONLY: summary function for the lower bound (ymin). Overrides the mean_se default."
        },
        "funMax": {
          "$ref": "#/$defs/SummaryFun",
          "description": "STAT SUMMARY / SUMMARY_BIN: summary function for the upper bound (ymax). Overrides the mean_se default."
        },
        "bins": {
          "type": "integer",
          "minimum": 1,
          "description": "STAT SUMMARY_BIN ONLY: number of bins (integer ≥ 1). Default 30 — advisory. Overridden by binwidth."
        },
        "binwidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "STAT SUMMARY_BIN ONLY: bin width in data units (must be greater than 0). Takes precedence over bins."
        },
        "boundary": {
          "type": "number",
          "description": "STAT SUMMARY_BIN ONLY: align a bin EDGE with this x value. Mutually exclusive with center."
        },
        "center": {
          "type": "number",
          "description": "STAT SUMMARY_BIN ONLY: align a bin CENTER with this x value. Mutually exclusive with boundary."
        },
        "closed": {
          "anyOf": [
            {
              "type": "string",
              "const": "right"
            },
            {
              "type": "string",
              "const": "left"
            }
          ],
          "description": "STAT SUMMARY_BIN ONLY: which edge of each bin is inclusive: \"right\" (default) or \"left\"."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for the errorbar geom: styling plus summary / summary_bin functions and summary_bin binning controls."
    },
    "LinerangeParams": {
      "$ref": "#/$defs/ErrorbarParams"
    },
    "PointrangeParams": {
      "type": "object",
      "properties": {
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Stem stroke width in px. Must be greater than 0. Default 1."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Opacity for stem and point. Default 1."
        },
        "size": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Mid-point radius in px. Default 2.5."
        },
        "shape": {
          "anyOf": [
            {
              "type": "string",
              "const": "circle"
            },
            {
              "type": "string",
              "const": "triangle"
            },
            {
              "type": "string",
              "const": "square"
            },
            {
              "type": "string",
              "const": "diamond"
            },
            {
              "type": "string",
              "const": "plus"
            },
            {
              "type": "string",
              "const": "cross"
            }
          ],
          "description": "Mid-point shape. Default \"circle\"."
        },
        "fun": {
          "anyOf": [
            {
              "type": "string",
              "const": "mean"
            },
            {
              "type": "string",
              "const": "median"
            },
            {
              "type": "string",
              "const": "sum"
            }
          ],
          "description": "STAT SUMMARY ONLY: center summary of y per x group. Default \"mean\" (mean_se when funMin/funMax omitted)."
        },
        "funMin": {
          "$ref": "#/$defs/SummaryFun",
          "description": "STAT SUMMARY ONLY: summary function for the lower bound (ymin). Overrides the mean_se default."
        },
        "funMax": {
          "$ref": "#/$defs/SummaryFun",
          "description": "STAT SUMMARY ONLY: summary function for the upper bound (ymax). Overrides the mean_se default."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for geom_pointrange (stem + mid point)."
    },
    "CrossbarParams": {
      "type": "object",
      "properties": {
        "width": {
          "type": "number",
          "exclusiveMinimum": 0,
          "maximum": 1,
          "description": "Box width: band-step fraction (band x) or fraction of continuous resolution (same rule as errorbar caps). Default 0.9."
        },
        "fatten": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Multiplier for the mid-line linewidth relative to params.linewidth / aes.linewidth. Default 2.5."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Outline and base mid-line stroke width in px. Default 1."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Box and mid-line opacity. Default 1."
        },
        "fun": {
          "anyOf": [
            {
              "type": "string",
              "const": "mean"
            },
            {
              "type": "string",
              "const": "median"
            },
            {
              "type": "string",
              "const": "sum"
            }
          ],
          "description": "STAT SUMMARY ONLY: center summary. Default \"mean\"."
        },
        "funMin": {
          "$ref": "#/$defs/SummaryFun",
          "description": "STAT SUMMARY ONLY: summary function for the lower bound (ymin). Overrides the mean_se default."
        },
        "funMax": {
          "$ref": "#/$defs/SummaryFun",
          "description": "STAT SUMMARY ONLY: summary function for the upper bound (ymax). Overrides the mean_se default."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for geom_crossbar (interval box + mid line)."
    },
    "RectParams": {
      "type": "object",
      "properties": {
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Outline stroke width in px when color is set. Must be greater than 0."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Rectangle opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "fillPaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient fill paint (not a data scale). Requires a solid fallback."
        },
        "strokePaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient outline paint (not a data scale). Requires a solid fallback."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Styling parameters for the rect geom (arbitrary xmin/xmax/ymin/ymax regions)."
    },
    "Bin2dParams": {
      "type": "object",
      "properties": {
        "bins": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Number of bins on each axis. Default 30. Applies equally to x and y in v1."
        },
        "binwidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Shared bin width in data units for both axes (overrides bins). Prefer when the scale units are meaningful."
        },
        "drop": {
          "type": "boolean",
          "description": "When true (default), omit zero-count bins from the output."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Cell opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Outline stroke width in px when color is set. Must be greater than 0."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for geom/stat bin_2d (2D rectangular binning heatmap). fill defaults to after_stat count."
    },
    "TileParams": {
      "type": "object",
      "properties": {
        "width": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Constant tile width in data units after position transform (band axes: fraction of the band step). Default: resolution of unique x centers (continuous) or 1 (band)."
        },
        "height": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Constant tile height in data units after position transform (band axes: fraction of the band step). Default: resolution of unique y centers (continuous) or 1 (band)."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Outline stroke width in px when color is set. Must be greater than 0."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Tile opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "fillPaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient fill paint (not a data scale). Requires a solid fallback."
        },
        "strokePaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient outline paint (not a data scale). Requires a solid fallback."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for the tile geom: center-sized cells (x/y + optional width/height)."
    },
    "RasterParams": {
      "type": "object",
      "properties": {
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Raster opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "hjust": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Horizontal justification of each cell over its x center (0–1). Default 0.5."
        },
        "vjust": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Vertical justification of each cell over its y center (0–1). Default 0.5."
        },
        "interpolate": {
          "type": "boolean",
          "const": false,
          "description": "Interpolation between cells. Only false (nearest / no interpolation) is supported."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for the raster geom: equal-cell dense grid (no per-cell stroke)."
    },
    "HexParams": {
      "type": "object",
      "properties": {
        "bins": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Approximate number of hex bins across the x range. Default 30."
        },
        "drop": {
          "type": "boolean",
          "description": "When true (default), omit zero-count hexes from the output."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Hex opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "linewidth": {
          "type": "number",
          "minimum": 0,
          "description": "Outline stroke width in px when color is set. Default 0 (no outline)."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for geom/stat hex (hexagonal 2D binning heatmap). fill defaults to after_stat count."
    },
    "PositionParams": {
      "type": "object",
      "properties": {
        "width": {
          "type": "number",
          "minimum": 0,
          "description": "JITTER ONLY: maximum horizontal jitter amount — data units on continuous x, band-step fractions on discrete x. Default 40% of the data resolution."
        },
        "height": {
          "type": "number",
          "minimum": 0,
          "description": "JITTER ONLY: maximum vertical jitter amount — data units on continuous y, band-step fractions on discrete y. Default 40% of the data resolution."
        },
        "seed": {
          "type": "integer",
          "minimum": 0,
          "description": "JITTER ONLY: RNG seed (a non-negative integer). Default 42. ggsvelte jitter is ALWAYS seeded so renders are reproducible (deliberate divergence from random jitter)."
        },
        "x": {
          "type": "number",
          "description": "NUDGE ONLY: horizontal offset — data units on continuous x, band-step fractions on discrete x. Default 0."
        },
        "y": {
          "type": "number",
          "description": "NUDGE ONLY: vertical offset — data units on continuous y, band-step fractions on discrete y. Default 0."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for the jitter (width, height, seed) and nudge (x, y) position adjustments."
    },
    "AreaParams": {
      "type": "object",
      "properties": {
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Area fill opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "fillPaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient fill paint (not a data scale). Requires a solid fallback."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Styling parameters for the area geom."
    },
    "RibbonParams": {
      "type": "object",
      "properties": {
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Ribbon fill opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Outline stroke width in px when an outline is drawn. Must be greater than 0. Default 1."
        },
        "outline": {
          "anyOf": [
            {
              "type": "string",
              "const": "both"
            },
            {
              "type": "string",
              "const": "upper"
            },
            {
              "type": "string",
              "const": "lower"
            },
            {
              "type": "string",
              "const": "full"
            }
          ],
          "description": "Which edges receive an outline stroke: \"both\" (default — upper and lower), \"upper\", \"lower\", or \"full\" (closed outline of the band). Strokes appear when aes.color / a color constant is set, or when strokePaint is set."
        },
        "orientation": {
          "anyOf": [
            {
              "type": "string",
              "const": "x"
            },
            {
              "type": "string",
              "const": "y"
            }
          ],
          "description": "Running-coordinate orientation: \"x\" (map x + ymin + ymax) or \"y\" (map y + xmin + xmax). When omitted, inferred from the complete channel contract; set explicitly if both contracts are mapped."
        },
        "lineend": {
          "anyOf": [
            {
              "type": "string",
              "const": "butt"
            },
            {
              "type": "string",
              "const": "round"
            },
            {
              "type": "string",
              "const": "square"
            }
          ],
          "description": "SVG stroke-linecap for outlines. Default \"butt\"."
        },
        "linejoin": {
          "anyOf": [
            {
              "type": "string",
              "const": "miter"
            },
            {
              "type": "string",
              "const": "round"
            },
            {
              "type": "string",
              "const": "bevel"
            }
          ],
          "description": "SVG stroke-linejoin for outlines. Default \"round\"."
        },
        "fillPaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient fill paint (not a data scale). Requires a solid fallback."
        },
        "strokePaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient outline paint (not a data scale). Requires a solid fallback."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Styling and orientation parameters for the ribbon geom."
    },
    "RuleIntercept": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "string"
        },
        {
          "type": "array",
          "items": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "string"
              }
            ]
          },
          "minItems": 1
        }
      ],
      "description": "A fixed intercept (or array of intercepts) in data units. Numbers for linear/log scales; ISO 8601 date strings (e.g. \"2026-01-01\") for time scales; category strings for band scales."
    },
    "RuleParams": {
      "type": "object",
      "properties": {
        "xintercept": {
          "$ref": "#/$defs/RuleIntercept",
          "description": "ANNOTATION FORM ONLY: draw a vertical rule at each of these fixed x positions. Mutually exclusive with mapping aes.x/aes.y on this layer."
        },
        "yintercept": {
          "$ref": "#/$defs/RuleIntercept",
          "description": "ANNOTATION FORM ONLY: draw a horizontal rule at each of these fixed y positions. Mutually exclusive with mapping aes.x/aes.y on this layer."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Rule opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Stroke width in px. Must be greater than 0. Default 1."
        },
        "strokePaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient stroke paint (not a data scale). Requires a solid fallback."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Styling parameters for the rule geom. The annotation form sets xintercept and/or yintercept here; the data-driven form maps aes.x OR aes.y instead (never both forms at once)."
    },
    "HlineParams": {
      "type": "object",
      "properties": {
        "yintercept": {
          "$ref": "#/$defs/RuleIntercept",
          "description": "ANNOTATION FORM ONLY: draw a horizontal rule at each of these fixed y positions. Mutually exclusive with mapping aes.y on this layer."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Rule opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Stroke width in px. Must be greater than 0. Default 1."
        },
        "strokePaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient stroke paint (not a data scale). Requires a solid fallback."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for the hline alias. Annotation form sets yintercept; data-driven form maps aes.y. Canonicalized by normalize to a rule layer."
    },
    "VlineParams": {
      "type": "object",
      "properties": {
        "xintercept": {
          "$ref": "#/$defs/RuleIntercept",
          "description": "ANNOTATION FORM ONLY: draw a vertical rule at each of these fixed x positions. Mutually exclusive with mapping aes.x on this layer."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Rule opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Stroke width in px. Must be greater than 0. Default 1."
        },
        "strokePaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient stroke paint (not a data scale). Requires a solid fallback."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for the vline alias. Annotation form sets xintercept; data-driven form maps aes.x. Canonicalized by normalize to a rule layer."
    },
    "SegmentParams": {
      "type": "object",
      "properties": {
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Segment opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Stroke width in px. Must be greater than 0. Default 1."
        },
        "lineend": {
          "anyOf": [
            {
              "type": "string",
              "const": "butt"
            },
            {
              "type": "string",
              "const": "round"
            },
            {
              "type": "string",
              "const": "square"
            }
          ],
          "description": "SVG stroke-linecap for segment ends. Default \"butt\"."
        },
        "strokePaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient stroke paint (not a data scale). Requires a solid fallback."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Styling parameters for the segment geom (finite line from (x,y) to (xend,yend))."
    },
    "RugParams": {
      "type": "object",
      "properties": {
        "sides": {
          "type": "string",
          "pattern": "^[bltr]+$",
          "minLength": 1,
          "description": "Which panel edges get ticks: any non-empty combination of \"b\" (bottom), \"l\" (left), \"t\" (top), \"r\" (right). Default \"bl\". Duplicates are treated as a set. Sides b/t require aes.x; sides l/r require aes.y."
        },
        "length": {
          "type": "number",
          "exclusiveMinimum": 0,
          "maximum": 1,
          "description": "Tick length as a fraction of the panel size along the tick axis (panel-fraction npc analogue of unit(0.03, \"npc\")). Default 0.03."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Tick opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Stroke width in px. Must be greater than 0. Default 1."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for geom_rug: panel-edge sides, panel-fraction length, and stroke styling."
    },
    "SpokeParams": {
      "type": "object",
      "properties": {
        "angle": {
          "type": "number",
          "description": "Constant spoke direction in radians when aes.angle is not mapped. 0 = +x, π/2 = +y."
        },
        "radius": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Constant spoke length in data units when aes.radius is not mapped. Must be greater than 0."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Spoke opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Stroke width in px. Must be greater than 0. Default 1."
        },
        "lineend": {
          "anyOf": [
            {
              "type": "string",
              "const": "butt"
            },
            {
              "type": "string",
              "const": "round"
            },
            {
              "type": "string",
              "const": "square"
            }
          ],
          "description": "SVG stroke-linecap for spoke ends. Default \"butt\"."
        },
        "strokePaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient stroke paint (not a data scale). Requires a solid fallback."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for geom spoke: optional constant angle/radius plus segment-like stroke styling."
    },
    "AblineParams": {
      "type": "object",
      "properties": {
        "slope": {
          "type": "number",
          "description": "Line slope (rise/run). Default 1 (identity line when intercept is 0)."
        },
        "intercept": {
          "type": "number",
          "description": "Y-intercept in data units. Default 0."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Line opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Stroke width in px. Must be greater than 0. Default 1."
        }
      },
      "additionalProperties": false,
      "description": "Annotation parameters for geom abline: y = intercept + slope · x, clipped to the panel. Annotation-only in v1 (no data-mapped slope/intercept)."
    },
    "AblineLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "abline",
          "description": "Abline geometry: one infinite reference line y = intercept + slope · x, clipped to the panel. Annotation form: fixed slope/intercept in params; does not inherit plot aes."
        },
        "stat": {
          "type": "string",
          "const": "identity",
          "description": "Abline layers use fixed params as-is."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Abline layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. Abline v1 ignores row data (annotation-only)."
        },
        "params": {
          "$ref": "#/$defs/AblineParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A slope/intercept reference-line layer. Annotation-only: set params.slope and params.intercept."
    },
    "CurveParams": {
      "type": "object",
      "properties": {
        "curvature": {
          "type": "number",
          "description": "Amount of bend away from the straight chord. 0 is a straight line; default 0.5. Positive bows to the right of the start→end direction when angle is 90."
        },
        "angle": {
          "type": "number",
          "description": "Control-point direction relative to the chord, in degrees. default 90 (perpendicular)."
        },
        "ncp": {
          "type": "integer",
          "minimum": 1,
          "maximum": 50,
          "description": "Smoothness density knob. Maps to tessellation sample count = max(8, ncp×8); not multi-control xspline. Default 5."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Curve opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Stroke width in px. Must be greater than 0. Default 1."
        },
        "lineend": {
          "anyOf": [
            {
              "type": "string",
              "const": "butt"
            },
            {
              "type": "string",
              "const": "round"
            },
            {
              "type": "string",
              "const": "square"
            }
          ],
          "description": "SVG stroke-linecap for curve ends. Default \"butt\"."
        },
        "strokePaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient stroke paint (not a data scale). Requires a solid fallback."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for geom curve: curvature/angle/ncp plus segment-like stroke styling."
    },
    "PolygonParams": {
      "type": "object",
      "properties": {
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Polygon fill/stroke opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Outline stroke width in px. Must be greater than 0. Default matches line (1.5)."
        },
        "fillPaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient fill paint (not a data scale). Requires a solid fallback."
        },
        "strokePaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient stroke paint (not a data scale). Requires a solid fallback."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Styling parameters for the polygon geom (closed filled path from (x,y) vertices)."
    },
    "MapParams": {
      "type": "object",
      "required": [
        "map"
      ],
      "properties": {
        "map": {
          "$ref": "#/$defs/DataRef",
          "description": "Fortified map coordinates ({ values }, { columns }, or { name } against spec.datasets). Must include long+lat or x+y, plus a region id column."
        },
        "mapId": {
          "type": "string",
          "minLength": 1,
          "description": "Join column name in the map data (matched to aes.map_id). Default: \"region\", then \"id\"."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Region fill opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Region outline stroke width in px. Must be greater than 0. Default 1.5."
        },
        "fillPaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient fill paint (not a data scale)."
        },
        "strokePaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient stroke paint (not a data scale)."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for geom_map: fortified map DataRef plus optional join column and polygon styling."
    },
    "SfParams": {
      "type": "object",
      "properties": {
        "geometry": {
          "type": "string",
          "minLength": 1,
          "description": "Name of the data column holding GeoJSON Geometry JSON strings. Default \"geometry\". Already-projected coordinates only."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Mark opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Stroke width in px for lines/polygon outlines. Must be greater than 0."
        },
        "size": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Point radius in px when geometries are Point/MultiPoint."
        },
        "fillPaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient fill paint (polygon family; not a data scale)."
        },
        "strokePaint": {
          "$ref": "#/$defs/GradientPaint",
          "description": "Within-mark gradient stroke paint (not a data scale)."
        },
        "glow": {
          "$ref": "#/$defs/GlowSpec",
          "description": "Bounded within-mark glow treatment (not theme decoration)."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for geom_sf: portable GeoJSON Geometry column plus styling. Interior rings are even-odd holes; GeometryCollection expands. Use coord_sf for fixed-aspect maps (CRS reproject deferred)."
    },
    "TextParams": {
      "type": "object",
      "properties": {
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Text opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "size": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Font size in px. Must be greater than 0. Default 11."
        },
        "anchor": {
          "anyOf": [
            {
              "type": "string",
              "const": "start"
            },
            {
              "type": "string",
              "const": "middle"
            },
            {
              "type": "string",
              "const": "end"
            }
          ],
          "description": "Horizontal text anchor relative to the (x, y) position: \"start\", \"middle\" (default), or \"end\"."
        },
        "dx": {
          "type": "number",
          "description": "Horizontal offset in px applied after positioning. Default 0."
        },
        "dy": {
          "type": "number",
          "description": "Vertical offset in px applied after positioning (positive = down). Default 0."
        }
      },
      "additionalProperties": false,
      "description": "Styling parameters for the text geom (no collision detection: labels draw exactly where placed)."
    },
    "LabelParams": {
      "type": "object",
      "properties": {
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Label opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "size": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Font size in px. Must be greater than 0. Default 11."
        },
        "anchor": {
          "anyOf": [
            {
              "type": "string",
              "const": "start"
            },
            {
              "type": "string",
              "const": "middle"
            },
            {
              "type": "string",
              "const": "end"
            }
          ],
          "description": "Horizontal text anchor relative to the (x, y) position: \"start\", \"middle\" (default), or \"end\"."
        },
        "dx": {
          "type": "number",
          "description": "Horizontal offset in px applied after positioning. Default 0."
        },
        "dy": {
          "type": "number",
          "description": "Vertical offset in px applied after positioning (positive = down). Default 0."
        },
        "padding": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Uniform box padding around the text in px. Default 3."
        },
        "radius": {
          "type": "number",
          "minimum": 0,
          "description": "Corner radius of the background box in px. Default 3."
        },
        "linewidth": {
          "type": "number",
          "minimum": 0,
          "description": "Box outline stroke width in px. Default 0.5."
        }
      },
      "additionalProperties": false,
      "description": "Styling parameters for the label geom (text with background box; no collision detection)."
    },
    "RenderBackend": {
      "anyOf": [
        {
          "type": "string",
          "const": "svg"
        },
        {
          "type": "string",
          "const": "canvas"
        },
        {
          "type": "string",
          "const": "auto"
        }
      ],
      "description": "Rendering backend for this layer: \"svg\" (DOM marks — accessible, copyable), \"canvas\" (fast raster for high mark counts), or \"auto\" (default — canvas above the mark-count threshold of 2000, with an advisory). Text layers always render as SVG. renderToSVGString ignores this and renders everything as SVG."
    },
    "StackablePosition": {
      "anyOf": [
        {
          "type": "string",
          "const": "stack"
        },
        {
          "type": "string",
          "const": "fill"
        },
        {
          "type": "string",
          "const": "dodge"
        },
        {
          "type": "string",
          "const": "identity"
        }
      ],
      "description": "Position adjustment: \"stack\" piles grouped values (positive up, negative down), \"fill\" stacks to proportions of 1, \"dodge\" places groups side by side, \"identity\" leaves positions unchanged."
    },
    "IdentityOrUniqueStat": {
      "anyOf": [
        {
          "type": "string",
          "const": "identity",
          "description": "Draw each data row as-is (no aggregation or row filter)."
        },
        {
          "type": "string",
          "const": "unique",
          "description": "Drop duplicate rows on the combination of mapped aesthetic fields before drawing; first occurrence wins. Panel-local."
        }
      ],
      "description": "Layer stat: \"identity\" (default) or \"unique\" (dedupe mapped aesthetics, first wins)."
    },
    "PointLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "point",
          "description": "Point geometry: one mark per data row. Use for scatter plots, dot plots, bubbles, and correlation views."
        },
        "stat": {
          "anyOf": [
            {
              "type": "string",
              "const": "identity",
              "description": "Draw each data row as-is (default)."
            },
            {
              "type": "string",
              "const": "unique",
              "description": "Drop duplicate rows on mapped aesthetics before drawing; first wins."
            },
            {
              "type": "string",
              "const": "summary_bin",
              "description": "Bin continuous x and summarize y per (group × bin); default mean ± se."
            },
            {
              "type": "string",
              "const": "manual",
              "description": "Portable named per-group transform (params.fun required: first|last|mean|median|min|max|sum;)."
            },
            {
              "type": "string",
              "const": "sum",
              "description": "Aggregate coincident (x, y); size defaults to {stat:\"n\"} (geom_count)."
            }
          ],
          "description": "Point stat: \"identity\" (default), \"unique\", \"summary_bin\", \"manual\", or \"sum\"."
        },
        "position": {
          "anyOf": [
            {
              "type": "string",
              "const": "identity"
            },
            {
              "type": "string",
              "const": "jitter"
            },
            {
              "type": "string",
              "const": "nudge"
            }
          ],
          "description": "Position adjustment: \"identity\" (default), \"jitter\" (seeded random offsets — configure with positionParams.width/height/seed), or \"nudge\" (fixed offsets — positionParams.x/y)."
        },
        "positionParams": {
          "$ref": "#/$defs/PositionParams"
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/PointParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A scatter/point layer. Requires x and y channels (inherited from plot aes or set in the layer's aes)."
    },
    "LineLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "line",
          "description": "Line geometry: connects points in x order, one line per group (groups derive from discrete aesthetics such as color, or from aes.group). Use for time series, trends, and line charts. With stat ecdf, pair with step curves; with stat bin (freqpoly alias), y is computed from counts/density; with stat connect, successive points expand into connection vertices."
        },
        "stat": {
          "anyOf": [
            {
              "type": "string",
              "const": "identity",
              "description": "Draw each data row as-is (default — map aes.y)."
            },
            {
              "type": "string",
              "const": "unique",
              "description": "Drop duplicate rows on mapped aesthetics before drawing (first wins;)."
            },
            {
              "type": "string",
              "const": "bin",
              "description": "Continuous x binned; the canonical form of geom freqpoly. Do NOT map aes.y to a field; y defaults to {\"stat\": \"count\"}."
            },
            {
              "type": "string",
              "const": "align",
              "description": "Interpolate each group onto the union of finite x values so continuous-x stack/fill aligns. Outside a group's x range y is 0."
            },
            {
              "type": "string",
              "const": "connect",
              "description": "Expand successive points into connection vertices (params.connection: hv|vh|mid|linear;). Expands in x order; geometry does not re-sort after connect."
            },
            {
              "type": "string",
              "const": "summary_bin",
              "description": "Bin continuous x and summarize y per (group × bin); default mean ± se; connect centers in x order."
            },
            {
              "type": "string",
              "const": "manual",
              "description": "Portable named per-group transform (params.fun required: first|last|mean|median|min|max|sum;)."
            },
            {
              "type": "string",
              "const": "ecdf",
              "description": "Empirical CDF of x; y defaults to {\"stat\": \"ecdf\"} — do NOT map aes.y to a field. Prefer params.curve \"step-hv\" for ECDF stairs."
            }
          ],
          "description": "Line stat: \"identity\" (default), \"unique\", \"bin\", \"align\", \"connect\", \"summary_bin\", \"manual\", or \"ecdf\"."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Line layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/LineParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A line layer. Identity: requires x and y. Bin (freqpoly): requires continuous x; y is computed by the bin stat. Ecdf: requires x only (y is computed). Rows are sorted by x within each group before connecting."
    },
    "StepLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "step",
          "description": "Step-line geometry: connect points with hv/vh/mid stairs. Same channels as line; ordered by x within groups."
        },
        "stat": {
          "type": "string",
          "const": "identity",
          "description": "Step layers draw the data as-is."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Step layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data."
        },
        "params": {
          "$ref": "#/$defs/StepParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A step-line layer. Requires x and y. params.direction is hv (default), vh, or mid."
    },
    "PathLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "path",
          "description": "Path geometry: connects points in data (row) order within each group — unlike line, which sorts by x. Use for trajectories, loops, connected scatterplots, and ellipse rings (stat ellipse). With stat connect, successive points expand into connection vertices."
        },
        "stat": {
          "anyOf": [
            {
              "type": "string",
              "const": "identity",
              "description": "Draw each data row as-is (default)."
            },
            {
              "type": "string",
              "const": "unique",
              "description": "Drop duplicate rows on mapped aesthetics before drawing (first wins;)."
            },
            {
              "type": "string",
              "const": "connect",
              "description": "Expand successive points into connection vertices (params.connection: hv|vh|mid|linear; default hv;). stat_connect default geom is path."
            },
            {
              "type": "string",
              "const": "manual",
              "description": "Portable named per-group transform (params.fun required: first|last|mean|median|min|max|sum;)."
            },
            {
              "type": "string",
              "const": "ellipse",
              "description": "Bivariate normal confidence ellipse per group. Emits perimeter samples suitable for path; requires quantitative x and y."
            }
          ],
          "description": "Path stat: \"identity\" (default), \"unique\", \"connect\", \"manual\", or \"ellipse\"."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Path layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/PathParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A path layer. Identity/connect/manual: requires x and y; rows stay in data order. Ellipse: quantitative x and y; one closed ring per group."
    },
    "ColLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "col",
          "description": "Column geometry: one rectangle per data row, from the y baseline (zero) to the row's y value. Use when the data already contains the bar heights — prefer over GeomBar, which counts or bins."
        },
        "stat": {
          "$ref": "#/$defs/IdentityOrUniqueStat"
        },
        "position": {
          "$ref": "#/$defs/StackablePosition"
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/ColParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A column (pre-computed bar) layer. Requires x (discrete) and y (the bar height) channels. Default position \"stack\"."
    },
    "BarLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "bar",
          "description": "Bar geometry with counting or binning: one rectangle per distinct x value (stat count, discrete x) or per bin (stat bin, continuous x). Do not map aes.y — the stat computes it. Prefer GeomCol when bar heights are already in the data."
        },
        "stat": {
          "anyOf": [
            {
              "type": "string",
              "const": "count"
            },
            {
              "type": "string",
              "const": "bin"
            }
          ],
          "description": "The bar layer's stat: \"count\" (default — rows counted per distinct x value and group) or \"bin\" (continuous x binned; the canonical form of the histogram geom). Map aes.weight to sum weights instead of counting. y defaults to {\"stat\": \"count\"}."
        },
        "position": {
          "$ref": "#/$defs/StackablePosition"
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/BarParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A counting/binning bar layer. Requires the x channel; y is computed by the stat. Default position \"stack\". Use geom \"col\" when the data already contains the heights."
    },
    "HistogramLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "histogram",
          "description": "Histogram geometry: a continuous x variable divided into bins, one bar per bin whose height is the count of rows (or the sum of aes.weight). Do not map aes.y — the bin stat computes it. Canonicalized by normalize() to a bar layer with stat bin."
        },
        "stat": {
          "type": "string",
          "const": "bin",
          "description": "Histogram layers bin continuous x values. y defaults to {\"stat\": \"count\"}; set y to {\"stat\": \"density\"} for a normalized histogram."
        },
        "position": {
          "$ref": "#/$defs/StackablePosition"
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/BarParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A histogram layer (alias for bar + stat bin). Requires a continuous x channel; y is computed by the bin stat. Default position \"stack\". Set params.binwidth or params.bins (default 30, with an advisory)."
    },
    "FreqpolyLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "freqpoly",
          "description": "Frequency polygon: continuous x binned like a histogram, drawn as a line through bin centers. Do not map aes.y — the bin stat computes it. Canonicalized by normalize() to a line layer with stat bin."
        },
        "stat": {
          "type": "string",
          "const": "bin",
          "description": "Freqpoly layers bin continuous x values. y defaults to {\"stat\": \"count\"}; set y to {\"stat\": \"density\"} for a density polygon."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Freqpoly layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/LineParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A frequency-polygon layer (alias for line + stat bin). Requires continuous x; y is computed by the bin stat. Default position \"identity\". Set params.binwidth or params.bins (default 30, with an advisory)."
    },
    "SmoothLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "smooth",
          "description": "Smooth geometry: a fitted trend line (with an optional confidence ribbon) over an x/y scatter, one fit per group. Use to reveal trends."
        },
        "stat": {
          "type": "string",
          "const": "smooth",
          "description": "Smooth layers fit lm or loess per group and evaluate the fit at params.n points."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Smooth layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/SmoothParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A fitted-trend layer. Requires quantitative x and y channels. Usually layered over a point layer of the same data."
    },
    "QuantileLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "quantile",
          "description": "Quantile geometry: linear quantile regression lines (y ~ x) at one or more conditional quantiles of y, one line per quantile per group."
        },
        "stat": {
          "type": "string",
          "const": "quantile",
          "description": "Quantile layers fit linear RQ per group × τ and evaluate on a grid of params.n points."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Quantile layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/QuantileParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A quantile-regression layer. Requires quantitative x and y. Default quantiles [0.25, 0.5, 0.75]. v1 is linear y~x only (no rqss)."
    },
    "QqLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "qq",
          "description": "Q–Q scatter: sample quantiles vs theoretical normal quantiles. Requires aes.sample."
        },
        "stat": {
          "type": "string",
          "const": "qq",
          "description": "Q–Q quantile pairing (default for this geom)."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "qq layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/QqParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A Q–Q point layer. Requires the sample channel."
    },
    "QqLineLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "qq_line",
          "description": "Q–Q reference line: line through sample/theoretical quartile match, spanning the theoretical range of the Q–Q cloud. Requires aes.sample."
        },
        "stat": {
          "type": "string",
          "const": "qq_line",
          "description": "Q–Q line slope/intercept from quartile match (default for this geom)."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "qq_line layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/QqLineParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A Q–Q reference line layer. Requires the sample channel."
    },
    "ContourLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "contour",
          "description": "Contour geometry: isolines of a continuous z surface over a regular x×y grid. v1 draws open path polylines only (not filled bands)."
        },
        "stat": {
          "type": "string",
          "const": "contour",
          "description": "Contour layers run clean-room marching-squares isolines per group over a complete rectangular grid."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Contour layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/ContourParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A contour isoline layer. Requires continuous x, y, and z on a regular complete grid. Levels from params.breaks, binwidth, or bins (default 10)."
    },
    "ViolinLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "violin",
          "description": "Violin geometry: mirrored kernel density of continuous y at each discrete x (stat ydensity). One polygon per x×group. Default position dodge."
        },
        "stat": {
          "type": "string",
          "const": "ydensity",
          "description": "Violin layers run a y-oriented KDE per x category and group."
        },
        "position": {
          "anyOf": [
            {
              "type": "string",
              "const": "dodge"
            },
            {
              "type": "string",
              "const": "identity"
            }
          ],
          "description": "Position adjustment: \"dodge\" (default) or \"identity\"."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/ViolinParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A violin layer. Requires discrete x and continuous y. Densities are computed by the ydensity stat."
    },
    "BoxplotLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "boxplot",
          "description": "Box-and-whisker geometry: one box per x category (per group) summarizing the y distribution — hinges at the quartiles, whiskers to the furthest points within coef × IQR, outliers drawn individually."
        },
        "stat": {
          "type": "string",
          "const": "boxplot",
          "description": "Boxplot layers compute five-number summaries (type-7 quantiles, the R default) per group."
        },
        "position": {
          "anyOf": [
            {
              "type": "string",
              "const": "dodge"
            },
            {
              "type": "string",
              "const": "identity"
            }
          ],
          "description": "Position adjustment: \"dodge\" (default — grouped boxes sit side by side within each x band) or \"identity\"."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/BoxplotParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A boxplot layer. Requires a discrete x channel and a quantitative y channel."
    },
    "CountLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "count",
          "description": "Count geometry: point marks at unique (x, y) with size scaled by after_stat n (stat sum). Use for overplotting density on discrete or rounded coordinates."
        },
        "stat": {
          "type": "string",
          "const": "sum",
          "description": "Count layers run stat sum: n and prop per (group, x, y). size defaults to {\"stat\": \"n\"}."
        },
        "position": {
          "anyOf": [
            {
              "type": "string",
              "const": "identity"
            },
            {
              "type": "string",
              "const": "jitter"
            },
            {
              "type": "string",
              "const": "nudge"
            }
          ],
          "description": "Position: \"identity\" (default), \"jitter\", or \"nudge\"."
        },
        "positionParams": {
          "$ref": "#/$defs/PositionParams"
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data."
        },
        "params": {
          "$ref": "#/$defs/PointParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A count (overplotting) layer. Requires x and y. Default size is after_stat n."
    },
    "DotplotLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "dotplot",
          "description": "Dotplot geometry: stacked dots along a continuous x axis (histodot subset). Do not map aes.y — the bindot stat computes stack positions."
        },
        "stat": {
          "type": "string",
          "const": "bindot",
          "description": "Histodot bindot: fixed bins, one mark per observation stacked within (group × bin). y defaults to {\"stat\": \"stackpos\"}."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Dotplot layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/DotplotParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A stacked-dot layer. Requires continuous x; y is stackpos from bindot. Map fill/color for groups. v1: method histodot only."
    },
    "DensityLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "density",
          "description": "Density geometry: a smooth kernel density estimate of a continuous x variable, drawn as a filled area — a smoothed histogram alternative. One curve per group. Do NOT map aes.y — the density stat computes it."
        },
        "stat": {
          "type": "string",
          "const": "density",
          "description": "Density layers run a gaussian KDE per group (bandwidth: R's bw.nrd0 unless params.bw is set). y defaults to {\"stat\": \"density\"}; set y to {\"stat\": \"count\"} for count scaling."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Density layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/DensityParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A kernel-density layer. Requires a continuous x channel; y is computed by the density stat. Map fill (with alpha) for overlaid group comparisons."
    },
    "Density2dLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "density_2d",
          "description": "2D density geometry: bivariate KDE isolines over continuous x and y. Open path contours."
        },
        "stat": {
          "type": "string",
          "const": "density_2d",
          "description": "density_2d layers estimate a product-Gaussian KDE per group on an n×n grid and extract isolines."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "density_2d layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/Density2dParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A 2D density contour layer. Requires continuous x and y. Contours of estimated density (not a precomputed z grid)."
    },
    "Density2dFilledLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "density_2d_filled",
          "description": "2D density filled bands: bivariate KDE closed isoline rings filled by density level. Open rings dropped. Defaults fill to after_stat(level)."
        },
        "stat": {
          "type": "string",
          "const": "density_2d_filled",
          "description": "Same KDE + isolines as density_2d, keeping closed rings only for filled paths."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "density_2d_filled layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data."
        },
        "params": {
          "$ref": "#/$defs/Density2dParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A filled 2D density layer. Requires continuous x and y. Fill defaults to after_stat(level)."
    },
    "ErrorbarLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "errorbar",
          "description": "Errorbar geometry: a vertical range with caps at ymin and ymax, one per data row (identity stat) or per x group (summary stat)."
        },
        "stat": {
          "anyOf": [
            {
              "type": "string",
              "const": "identity",
              "description": "Map aes.ymin and aes.ymax to data fields (default)."
            },
            {
              "type": "string",
              "const": "unique",
              "description": "Drop duplicate rows on mapped aesthetics before drawing; first wins."
            },
            {
              "type": "string",
              "const": "summary",
              "description": "Compute y/ymin/ymax per x group from aes.y; default mean ± standard error."
            },
            {
              "type": "string",
              "const": "summary_bin",
              "description": "Bin continuous x and summarize y per (group × bin); default mean ± se."
            }
          ],
          "description": "The errorbar's stat: \"identity\" (default), \"unique\", \"summary\" (per x group), or \"summary_bin\" (per bin;)."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Errorbar layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/ErrorbarParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "An errorbar layer. Identity: requires x, ymin, ymax. Summary / summary_bin: requires x and y (bounds from params.fun/funMin/funMax, default mean_se)."
    },
    "LinerangeLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "linerange",
          "description": "Linerange geometry: a vertical stem from ymin to ymax without end caps."
        },
        "stat": {
          "anyOf": [
            {
              "type": "string",
              "const": "identity"
            },
            {
              "type": "string",
              "const": "summary"
            }
          ],
          "description": "Identity (map ymin/ymax) or summary (mean_se from aes.y) — same contract as errorbar."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Linerange layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef"
        },
        "params": {
          "$ref": "#/$defs/LinerangeParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A linerange layer. Identity: x, ymin, ymax. Summary: x, y. No caps (unlike errorbar)."
    },
    "PointrangeLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "pointrange",
          "description": "Pointrange geometry: vertical stem from ymin to ymax plus a point at (x, y)."
        },
        "stat": {
          "anyOf": [
            {
              "type": "string",
              "const": "identity"
            },
            {
              "type": "string",
              "const": "summary"
            }
          ],
          "description": "Identity (map y, ymin, ymax) or summary (center + mean_se bounds from aes.y)."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Pointrange layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef"
        },
        "params": {
          "$ref": "#/$defs/PointrangeParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A pointrange layer. Identity: x, y, ymin, ymax. Summary: x, y. Point size/shape via params or aes."
    },
    "CrossbarLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "crossbar",
          "description": "Crossbar geometry: a vertical interval box from ymin to ymax with a mid horizontal line at y."
        },
        "stat": {
          "anyOf": [
            {
              "type": "string",
              "const": "identity"
            },
            {
              "type": "string",
              "const": "summary"
            }
          ],
          "description": "Identity (map y, ymin, ymax) or summary (center + mean_se bounds from aes.y)."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Crossbar layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef"
        },
        "params": {
          "$ref": "#/$defs/CrossbarParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A crossbar layer. Identity: x, y, ymin, ymax. Box width uses the same resolution rule as errorbar caps. Mid-line linewidth = linewidth * fatten."
    },
    "RectLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "rect",
          "description": "Rectangle geometry: one rectangle per data row from mapped xmin/xmax/ymin/ymax edges. Use for arbitrary shaded regions and time bands."
        },
        "stat": {
          "$ref": "#/$defs/IdentityOrUniqueStat"
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Rect layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/RectParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A rectangle layer. Requires xmin, xmax, ymin, and ymax channels (quantitative edges)."
    },
    "TileLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "tile",
          "description": "Tile geometry: center-sized cells at (x, y) with optional width/height. Use for heatmaps and gridded categorical cells; supports stroke outlines."
        },
        "stat": {
          "type": "string",
          "const": "identity",
          "description": "Tile layers draw the data as-is."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Tile layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/TileParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A tile layer. Requires x and y channels; optional width/height (params or aes) size each cell after position transform."
    },
    "Bin2dLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "bin_2d",
          "description": "2D rectangular bin heatmap: partitions continuous x×y into a grid and maps fill to bin count by default. Empty bins are dropped unless params.drop is false."
        },
        "stat": {
          "type": "string",
          "const": "bin_2d",
          "description": "2D binning stat (default for this geom)."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "bin_2d layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/Bin2dParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A 2D bin heatmap layer. Requires continuous x and y; fill defaults to after_stat count."
    },
    "RasterLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "raster",
          "description": "Raster geometry: equal-cell grid at (x, y) with fill; optimized dense heatmaps without per-cell strokes. Irregular spacing warns and suggests geom tile."
        },
        "stat": {
          "type": "string",
          "const": "identity",
          "description": "Raster layers draw the data as-is."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Raster layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/RasterParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A raster layer. Requires x and y (regular spacing); fill maps cell color. No stroke. interpolate must be false when set."
    },
    "HexLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "hex",
          "description": "Hexagonal bin heatmap: partitions continuous x×y into a hexagonal lattice and maps fill to bin count by default."
        },
        "stat": {
          "type": "string",
          "const": "bin_hex",
          "description": "Hexagonal binning stat (default for this geom)."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "hex layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/HexParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A hexagonal bin heatmap layer. Requires continuous x and y; fill defaults to after_stat count."
    },
    "AreaLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "area",
          "description": "Area geometry: a filled region from the y baseline (zero) to the y value, connected in x order per group. Use for stacked composition-over-time charts. With stat align, series with different x samples share a common grid for stack/fill."
        },
        "stat": {
          "anyOf": [
            {
              "type": "string",
              "const": "identity",
              "description": "Draw each data row as-is (default)."
            },
            {
              "type": "string",
              "const": "unique",
              "description": "Drop duplicate rows on mapped aesthetics before drawing (first wins)."
            },
            {
              "type": "string",
              "const": "align",
              "description": "Interpolate each group onto the union of finite x values so continuous-x stack/fill aligns. Outside a group's x range y is 0."
            }
          ],
          "description": "Area stat: \"identity\" (default), \"unique\" (first-wins dedupe), or \"align\" (shared x grid for stacking)."
        },
        "position": {
          "$ref": "#/$defs/StackablePosition"
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/AreaParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "An area layer. Requires x and y channels; rows are sorted by x within each group. Default position \"stack\". Use stat \"align\" when groups have different continuous x samples."
    },
    "RibbonLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "ribbon",
          "description": "Ribbon geometry: a filled interval between two varying boundaries along a running coordinate. Map x+ymin+ymax (x orientation) or y+xmin+xmax (y orientation). Not a zero-baseline area."
        },
        "stat": {
          "$ref": "#/$defs/IdentityOrUniqueStat"
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Ribbon layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/RibbonParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A ribbon layer. Requires a running coordinate and both interval bounds (x+ymin+ymax or y+xmin+xmax). Rows are sorted along the running coordinate within each group."
    },
    "RuleLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "rule",
          "description": "Rule geometry: reference lines spanning the panel. Two forms: (1) annotation — set params.xintercept and/or params.yintercept to fixed data values and map neither aes.x nor aes.y; (2) data-driven — map exactly one of aes.x (vertical rules) or aes.y (horizontal rules) to a field. Never mix the forms in one layer."
        },
        "stat": {
          "$ref": "#/$defs/IdentityOrUniqueStat"
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Rule layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/RuleParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A reference-line layer. Annotation form: fixed intercepts in params. Data-driven form: map aes.x OR aes.y."
    },
    "HlineLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "hline",
          "description": "Horizontal reference-line alias. Canonicalized by normalize() to a rule layer. Annotation form: set params.yintercept. Data-driven form: map aes.y (inherited plot x is dropped so the one-axis rule contract holds)."
        },
        "stat": {
          "type": "string",
          "const": "identity",
          "description": "Hline layers draw the given positions as-is."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Hline layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/HlineParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A horizontal reference-line layer alias (normalize() → rule). Annotation: params.yintercept. Data-driven: map aes.y."
    },
    "VlineLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "vline",
          "description": "Vertical reference-line alias. Canonicalized by normalize() to a rule layer. Annotation form: set params.xintercept. Data-driven form: map aes.x (inherited plot y is dropped so the one-axis rule contract holds)."
        },
        "stat": {
          "type": "string",
          "const": "identity",
          "description": "Vline layers draw the given positions as-is."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Vline layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/VlineParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A vertical reference-line layer alias (normalize() → rule). Annotation: params.xintercept. Data-driven: map aes.x."
    },
    "JitterLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "jitter",
          "description": "Jittered point alias. Canonicalized by normalize() to a point layer with position jitter. Configure jitter amount via positionParams.width/height/seed."
        },
        "stat": {
          "type": "string",
          "const": "identity",
          "description": "Jitter layers draw the data as-is."
        },
        "position": {
          "type": "string",
          "const": "jitter",
          "description": "Jitter layers always use position \"jitter\" (the alias purpose)."
        },
        "positionParams": {
          "$ref": "#/$defs/PositionParams"
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/PointParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A scatter layer with position \"jitter\" (alias; normalize() → point). Requires x and y channels. Jitter width/height/seed live on positionParams."
    },
    "TextLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "text",
          "description": "Text geometry: one label per data row at (x, y). No collision detection — labels draw exactly where placed. Requires x, y, and label channels."
        },
        "stat": {
          "$ref": "#/$defs/IdentityOrUniqueStat"
        },
        "position": {
          "anyOf": [
            {
              "type": "string",
              "const": "identity"
            },
            {
              "type": "string",
              "const": "nudge"
            }
          ],
          "description": "Position adjustment: \"identity\" (default) or \"nudge\" (fixed offsets from the anchor — set positionParams.x/y; useful for labels beside marks)."
        },
        "positionParams": {
          "$ref": "#/$defs/PositionParams"
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/TextParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A text-label layer. Requires x, y, and label channels."
    },
    "LabelLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "label",
          "description": "Label geometry: text with a rounded rectangular background box. Requires x, y, and label channels. No collision detection."
        },
        "stat": {
          "type": "string",
          "const": "identity",
          "description": "Label layers draw the data as-is."
        },
        "position": {
          "anyOf": [
            {
              "type": "string",
              "const": "identity"
            },
            {
              "type": "string",
              "const": "nudge"
            }
          ],
          "description": "Position adjustment: \"identity\" (default) or \"nudge\" (fixed offsets — set positionParams.x/y)."
        },
        "positionParams": {
          "$ref": "#/$defs/PositionParams"
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/LabelParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A label layer (text + background box). Requires x, y, and label channels. color styles text/outline; fill styles the box."
    },
    "SegmentLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "segment",
          "description": "Segment geometry: one finite line per data row from (x, y) to (xend, yend). Unlike rule, endpoints are data-mapped and do not span the panel."
        },
        "stat": {
          "$ref": "#/$defs/IdentityOrUniqueStat"
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Segment layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/SegmentParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A finite segment layer. Requires x, y, xend, and yend channels."
    },
    "FunctionLayer": {
      "type": "object",
      "required": [
        "geom",
        "params"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "function",
          "description": "Function geometry: evaluate a named portable function y = f(x) on a grid and draw a path. Requires params.fun; domain from params.xlim, mapped x, or peer layers."
        },
        "stat": {
          "type": "string",
          "const": "function",
          "description": "Function layers evaluate a named registry function on a grid."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Function layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/FunctionParams",
          "description": "Function parameters (fun is required)."
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "An analytic function layer. y is computed as { stat: y }; do not map data y. Portable fun names only (no JS closures)."
    },
    "CurveLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "curve",
          "description": "Curve geometry: one curved connector per row from (x, y) to (xend, yend). Tessellated as a quadratic Bezier (curvature/angle/ncp). Requires field-mapped x, y, xend, and yend."
        },
        "stat": {
          "type": "string",
          "const": "identity",
          "description": "Curve layers draw the data as-is."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Curve layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/CurveParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A curved-segment layer. Requires x, y, xend, and yend field channels (like geom segment)."
    },
    "PolygonLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "polygon",
          "description": "Polygon geometry: closed filled paths from (x, y) vertices in data/row order within each group. Groups form separate polygons. No x-sort (unlike line/area). Holes/subgroup omitted in v1."
        },
        "stat": {
          "type": "string",
          "const": "identity",
          "description": "Polygon layers draw the data as-is."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Polygon layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/PolygonParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A closed polygon layer. Requires x and y channels; vertices connect in data order per group and close implicitly."
    },
    "MapLayer": {
      "type": "object",
      "required": [
        "geom",
        "params"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "map",
          "description": "Map geometry: join fortified region borders to value rows via aes.map_id and params.map. Renders closed filled paths per region."
        },
        "stat": {
          "type": "string",
          "const": "identity",
          "description": "Map layers expand joins then draw as-is."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Map layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local value data (region ids + fill aesthetics). When omitted, inherits plot data."
        },
        "params": {
          "$ref": "#/$defs/MapParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A choropleth/map layer. Requires aes.map_id and params.map. Coordinates come from the map data (long/lat or x/y)."
    },
    "SfLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "sf",
          "description": "Simple-features geometry: already-projected GeoJSON Geometry JSON strings in a data column. Point/line/polygon families (incl. GeometryCollection of one family) with even-odd holes; use coord_sf for fixed-aspect (CRS reproject deferred)."
        },
        "stat": {
          "type": "string",
          "const": "sf",
          "description": "Geometry expand: portable GeoJSON → drawable point/line/polygon parts."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "SF layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data."
        },
        "params": {
          "$ref": "#/$defs/SfParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "An sf geometry layer. Requires a geometry column of GeoJSON Geometry JSON strings (params.geometry, default \"geometry\"). Coordinates must already be projected. Default stat is \"sf\"."
    },
    "SfTextParams": {
      "type": "object",
      "properties": {
        "geometry": {
          "type": "string",
          "minLength": 1,
          "description": "Name of the data column holding GeoJSON Geometry JSON strings. Default \"geometry\"."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Text opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "size": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Font size in px. Must be greater than 0. Default 11."
        },
        "anchor": {
          "anyOf": [
            {
              "type": "string",
              "const": "start"
            },
            {
              "type": "string",
              "const": "middle"
            },
            {
              "type": "string",
              "const": "end"
            }
          ],
          "description": "Horizontal text anchor relative to the representative point: \"start\", \"middle\" (default), or \"end\"."
        },
        "dx": {
          "type": "number",
          "description": "Horizontal offset in px applied after positioning. Default 0."
        },
        "dy": {
          "type": "number",
          "description": "Vertical offset in px applied after positioning (positive = down). Default 0."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for geom_sf_text: geometry column plus text styling."
    },
    "SfTextLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "sf_text",
          "description": "Simple-features text labels: places aes.label at representative geometry points (Multi* → one label per part; stat_sf_coordinates)."
        },
        "stat": {
          "type": "string",
          "const": "sf_coordinates",
          "description": "Extract (x,y) representative points from geometry (Multi* → one point per part)."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "SF text layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data."
        },
        "params": {
          "$ref": "#/$defs/SfTextParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "An sf text layer. Requires aes.label and a geometry column (params.geometry, default \"geometry\"). Does not require aes.x/y."
    },
    "SfLabelParams": {
      "type": "object",
      "properties": {
        "geometry": {
          "type": "string",
          "minLength": 1,
          "description": "Name of the data column holding GeoJSON Geometry JSON strings. Default \"geometry\"."
        },
        "alpha": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Label opacity. Must be between 0 and 1 (inclusive). Default 1."
        },
        "size": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Font size in px. Must be greater than 0. Default 11."
        },
        "anchor": {
          "anyOf": [
            {
              "type": "string",
              "const": "start"
            },
            {
              "type": "string",
              "const": "middle"
            },
            {
              "type": "string",
              "const": "end"
            }
          ],
          "description": "Horizontal text anchor relative to the representative point: \"start\", \"middle\" (default), or \"end\"."
        },
        "dx": {
          "type": "number",
          "description": "Horizontal offset in px applied after positioning. Default 0."
        },
        "dy": {
          "type": "number",
          "description": "Vertical offset in px applied after positioning (positive = down). Default 0."
        },
        "padding": {
          "type": "number",
          "minimum": 0,
          "description": "Box padding around the text in px. Default 3."
        },
        "radius": {
          "type": "number",
          "minimum": 0,
          "description": "Box corner radius in px. Default 3."
        },
        "linewidth": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Box stroke width in px. Default 0.5."
        }
      },
      "additionalProperties": false,
      "description": "Parameters for geom_sf_label: geometry column, text styling, and label box chrome."
    },
    "SfLabelLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "sf_label",
          "description": "Simple-features labels with background boxes: places aes.label at representative geometry points with a measured rounded rect (Multi* → one label per part). color=ink+box stroke; fill=box background."
        },
        "stat": {
          "type": "string",
          "const": "sf_coordinates",
          "description": "Extract (x,y) representative points from geometry (Multi* → one point per part)."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "SF label layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data."
        },
        "params": {
          "$ref": "#/$defs/SfLabelParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "An sf label layer with a background box. Requires aes.label and a geometry column. Does not require aes.x/y."
    },
    "BlankParams": {
      "type": "object",
      "properties": {},
      "additionalProperties": false,
      "description": "Blank layers have no paint/stat params; the object exists only so LayerSpec has a uniform optional params field."
    },
    "BlankLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "blank",
          "description": "Blank geometry: contributes mapped aesthetics to scale training and layout without drawing marks or hit targets. No channels are required; whatever is mapped trains its scale."
        },
        "stat": {
          "type": "string",
          "const": "identity",
          "description": "Blank layers pass data through for scale training only."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Blank layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data."
        },
        "params": {
          "$ref": "#/$defs/BlankParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "An empty layer that trains scales from mapped aesthetics without emitting geometry."
    },
    "RugLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "rug",
          "description": "Rug geometry: short ticks along panel edges for each observation. Map aes.x for bottom/top sides and/or aes.y for left/right sides."
        },
        "stat": {
          "type": "string",
          "const": "identity",
          "description": "Rug layers draw the data as-is."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Rug layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/RugParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A marginal rug layer. Default sides \"bl\" require both x and y; restrict sides when only one channel is mapped."
    },
    "SpokeLayer": {
      "type": "object",
      "required": [
        "geom"
      ],
      "properties": {
        "geom": {
          "type": "string",
          "const": "spoke",
          "description": "Spoke geometry: one finite segment per row from (x, y) in direction angle (radians) with length radius. Endpoints are derived as xend = x + radius·cos(angle), yend = y + radius·sin(angle) in data space, then transformed like x/y. Requires continuous x and y."
        },
        "stat": {
          "type": "string",
          "const": "identity",
          "description": "Spoke layers draw the data as-is."
        },
        "position": {
          "type": "string",
          "const": "identity",
          "description": "Spoke layers use identity positioning."
        },
        "render": {
          "$ref": "#/$defs/RenderBackend"
        },
        "aes": {
          "$ref": "#/$defs/Aes"
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Optional layer-local data. When omitted, the layer inherits plot-level data. When present, it may use inline rows, inline columns, or a named dataset (spec.datasets or runtime)."
        },
        "params": {
          "$ref": "#/$defs/SpokeParams"
        },
        "inspect": {
          "type": "boolean",
          "const": false,
          "description": "Set false to exclude this layer from inspection: its marks never become tooltip, hover, or keyboard-traversal candidates. For decorative layers (background bands, reference shading) whose marks would otherwise capture the pointer — an area mark contains the pointer everywhere it is painted, so it outranks every point and stroke beneath it. Portable: it travels with the spec, so headless renders and re-imported JSON agree."
        }
      },
      "additionalProperties": false,
      "description": "A spoke layer. Requires x and y; angle and radius from aes and/or params (constants). Angle is radians."
    },
    "LayerSpec": {
      "anyOf": [
        {
          "$ref": "#/$defs/PointLayer"
        },
        {
          "$ref": "#/$defs/LineLayer"
        },
        {
          "$ref": "#/$defs/PathLayer"
        },
        {
          "$ref": "#/$defs/StepLayer"
        },
        {
          "$ref": "#/$defs/ColLayer"
        },
        {
          "$ref": "#/$defs/BarLayer"
        },
        {
          "$ref": "#/$defs/HistogramLayer"
        },
        {
          "$ref": "#/$defs/FreqpolyLayer"
        },
        {
          "$ref": "#/$defs/AreaLayer"
        },
        {
          "$ref": "#/$defs/RibbonLayer"
        },
        {
          "$ref": "#/$defs/RuleLayer"
        },
        {
          "$ref": "#/$defs/HlineLayer"
        },
        {
          "$ref": "#/$defs/VlineLayer"
        },
        {
          "$ref": "#/$defs/JitterLayer"
        },
        {
          "$ref": "#/$defs/TextLayer"
        },
        {
          "$ref": "#/$defs/LabelLayer"
        },
        {
          "$ref": "#/$defs/SmoothLayer"
        },
        {
          "$ref": "#/$defs/QuantileLayer"
        },
        {
          "$ref": "#/$defs/QqLayer"
        },
        {
          "$ref": "#/$defs/QqLineLayer"
        },
        {
          "$ref": "#/$defs/ContourLayer"
        },
        {
          "$ref": "#/$defs/BoxplotLayer"
        },
        {
          "$ref": "#/$defs/ViolinLayer"
        },
        {
          "$ref": "#/$defs/DensityLayer"
        },
        {
          "$ref": "#/$defs/Density2dLayer"
        },
        {
          "$ref": "#/$defs/Density2dFilledLayer"
        },
        {
          "$ref": "#/$defs/DotplotLayer"
        },
        {
          "$ref": "#/$defs/CountLayer"
        },
        {
          "$ref": "#/$defs/ErrorbarLayer"
        },
        {
          "$ref": "#/$defs/LinerangeLayer"
        },
        {
          "$ref": "#/$defs/PointrangeLayer"
        },
        {
          "$ref": "#/$defs/CrossbarLayer"
        },
        {
          "$ref": "#/$defs/MapLayer"
        },
        {
          "$ref": "#/$defs/RectLayer"
        },
        {
          "$ref": "#/$defs/TileLayer"
        },
        {
          "$ref": "#/$defs/Bin2dLayer"
        },
        {
          "$ref": "#/$defs/RasterLayer"
        },
        {
          "$ref": "#/$defs/HexLayer"
        },
        {
          "$ref": "#/$defs/SegmentLayer"
        },
        {
          "$ref": "#/$defs/FunctionLayer"
        },
        {
          "$ref": "#/$defs/PolygonLayer"
        },
        {
          "$ref": "#/$defs/AblineLayer"
        },
        {
          "$ref": "#/$defs/CurveLayer"
        },
        {
          "$ref": "#/$defs/SfLayer"
        },
        {
          "$ref": "#/$defs/SfTextLayer"
        },
        {
          "$ref": "#/$defs/SfLabelLayer"
        },
        {
          "$ref": "#/$defs/BlankLayer"
        },
        {
          "$ref": "#/$defs/SpokeLayer"
        },
        {
          "$ref": "#/$defs/RugLayer"
        }
      ],
      "description": "One plot layer. The `geom` field selects the geometry and determines which stat, position, and params are allowed."
    },
    "DomainValue": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "number"
        },
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "description": "One domain entry: a number (linear/log), an ISO 8601 date string (time), or a category value (band/ordinal)."
    },
    "TemporalParserSpec": {
      "anyOf": [
        {
          "anyOf": [
            {
              "type": "string",
              "const": "iso"
            },
            {
              "type": "string",
              "const": "year"
            },
            {
              "type": "string",
              "const": "ym"
            },
            {
              "type": "string",
              "const": "my"
            },
            {
              "type": "string",
              "const": "yq"
            },
            {
              "type": "string",
              "const": "md"
            },
            {
              "type": "string",
              "const": "ymd"
            },
            {
              "type": "string",
              "const": "ydm"
            },
            {
              "type": "string",
              "const": "mdy"
            },
            {
              "type": "string",
              "const": "myd"
            },
            {
              "type": "string",
              "const": "dmy"
            },
            {
              "type": "string",
              "const": "dym"
            },
            {
              "type": "string",
              "const": "ymd_hm"
            },
            {
              "type": "string",
              "const": "ymd_hms"
            },
            {
              "type": "string",
              "const": "ydm_hm"
            },
            {
              "type": "string",
              "const": "ydm_hms"
            },
            {
              "type": "string",
              "const": "mdy_hm"
            },
            {
              "type": "string",
              "const": "mdy_hms"
            },
            {
              "type": "string",
              "const": "myd_hm"
            },
            {
              "type": "string",
              "const": "myd_hms"
            },
            {
              "type": "string",
              "const": "dmy_hm"
            },
            {
              "type": "string",
              "const": "dmy_hms"
            },
            {
              "type": "string",
              "const": "dym_hm"
            },
            {
              "type": "string",
              "const": "dym_hms"
            }
          ]
        },
        {
          "type": "object",
          "required": [
            "format"
          ],
          "properties": {
            "format": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128,
              "description": "Closed strftime-style input grammar (maximum 128 characters and 32 tokens). Supported tokens: %Y, %m, %d, %H, %M, %S, %L, %z, %q, and %%."
            }
          },
          "additionalProperties": false
        },
        {
          "type": "object",
          "required": [
            "epoch"
          ],
          "properties": {
            "epoch": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "seconds"
                },
                {
                  "type": "string",
                  "const": "milliseconds"
                }
              ]
            }
          },
          "additionalProperties": false
        }
      ],
      "description": "A deterministic temporal parser name, exact closed format, or epoch unit. JavaScript callbacks and regular expressions are not portable parsers."
    },
    "ScaleExpansion": {
      "type": "object",
      "properties": {
        "mult": {
          "anyOf": [
            {
              "type": "number",
              "minimum": 0
            },
            {
              "type": "array",
              "items": {
                "type": "number",
                "minimum": 0
              },
              "minItems": 2,
              "maxItems": 2
            }
          ],
          "description": "Multiplicative display padding as a fraction of the (transformed) domain span. A scalar pads both ends; a [lower, upper] tuple pads each end. Non-negative and finite."
        },
        "add": {
          "anyOf": [
            {
              "type": "number",
              "minimum": 0
            },
            {
              "type": "array",
              "items": {
                "type": "number",
                "minimum": 0
              },
              "minItems": 2,
              "maxItems": 2
            }
          ],
          "description": "Additive display padding in (transformed) scale units. A scalar pads both ends; a [lower, upper] tuple pads each end. Non-negative and finite."
        }
      },
      "additionalProperties": false,
      "description": "Display-domain expansion. Padding is applied after nice in transformed space and never widens the OOB limits. `{ mult: 0, add: 0 }` disables padding."
    },
    "PositionScaleSpec": {
      "allOf": [
        {
          "type": "object",
          "properties": {
            "type": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "linear"
                },
                {
                  "type": "string",
                  "const": "log"
                },
                {
                  "type": "string",
                  "const": "time"
                },
                {
                  "type": "string",
                  "const": "band"
                },
                {
                  "type": "string",
                  "const": "binned"
                }
              ],
              "description": "Scale type: \"linear\" (default for numbers), \"time\" (temporal fields; ISO strings or Date values), \"band\" (discrete categories), \"binned\" (quantitative values assigned to ordered bins). \"log\" is an accepted authored alias that canonicalizes to { type: \"linear\", transform: \"log10\" }. Omit to infer from the field type."
            },
            "transform": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "identity"
                },
                {
                  "type": "string",
                  "const": "log10"
                },
                {
                  "type": "string",
                  "const": "sqrt"
                }
              ],
              "description": "Pre-stat position transform applied after parsing and before grouping-sensitive stats/positions. \"identity\" (default), \"log10\" (base-10; source values must be > 0), \"sqrt\" (source values must be >= 0). Only \"identity\" is permitted on time scales."
            },
            "temporalKind": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "date"
                },
                {
                  "type": "string",
                  "const": "datetime"
                },
                {
                  "type": "string",
                  "const": "time"
                },
                {
                  "type": "string",
                  "const": "monthDay"
                }
              ],
              "description": "Temporal precision intent. \"date\" uses calendar dates; \"datetime\" uses instants; \"time\" is time-of-day (portable numbers are seconds since midnight); \"monthDay\" collapses the year, so the same calendar day from any year shares one position — values parse with the \"md\" parser and resolve into a fixed leap reference year, and year, clock, weekday and zone label tokens are rejected. A month-day window cannot cross the year boundary. Supplying this option requests a time scale."
            },
            "parse": {
              "$ref": "#/$defs/TemporalParserSpec",
              "description": "Explicit deterministic parser for temporal source values. Omit for value-driven inference."
            },
            "parseFailure": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "error"
                },
                {
                  "type": "string",
                  "const": "censor"
                }
              ],
              "description": "Explicit parser failure policy: \"error\" (default) stops with bounded evidence; \"censor\" converts invalid values to missing and emits a warning."
            },
            "timezone": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128,
              "description": "IANA timezone used for timezone-less temporal input. Default \"UTC\". Invalid zones fail with an actionable diagnostic."
            },
            "disambiguation": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "compatible"
                },
                {
                  "type": "string",
                  "const": "earlier"
                },
                {
                  "type": "string",
                  "const": "later"
                },
                {
                  "type": "string",
                  "const": "reject"
                }
              ],
              "description": "DST gap/fold policy for IANA local times. Default \"reject\"; choose \"earlier\", \"later\", or Temporal-compatible behavior explicitly."
            },
            "dateBreaks": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128,
              "pattern": "^[ ]*(?:[1-9][0-9]{0,5}|1000000)[ ]+(?:millisecond|second|minute|hour|day|week|month|quarter|year)s?[ ]*$",
              "description": "A positive integer calendar interval such as \"2 weeks\", \"3 months\", or \"10 years\". Canonical units are millisecond, second, minute, hour, day, week, month, quarter, and year."
            },
            "dateMinorBreaks": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128,
              "pattern": "^[ ]*(?:[1-9][0-9]{0,5}|1000000)[ ]+(?:millisecond|second|minute|hour|day|week|month|quarter|year)s?[ ]*$",
              "description": "A positive integer calendar interval such as \"2 weeks\", \"3 months\", or \"10 years\". Canonical units are millisecond, second, minute, hour, day, week, month, quarter, and year."
            },
            "dateLabels": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128,
              "pattern": "^(?:[^%]|%(?:Y|y|m|b|B|d|e|a|A|H|I|M|S|L|p|q|z|Z|%))+$",
              "description": "Strict temporal label format. Supported tokens: %Y %y %m %b %B %d %e %a %A %H %I %M %S %L %p %q %z %Z %%."
            },
            "locale": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128,
              "description": "BCP 47 locale for temporal labels. Default \"en-US\". JSON Schema bounds the portable string shape; runtime validation canonicalizes the tag and verifies Intl support before rendering."
            },
            "weekStart": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "monday"
                },
                {
                  "type": "string",
                  "const": "tuesday"
                },
                {
                  "type": "string",
                  "const": "wednesday"
                },
                {
                  "type": "string",
                  "const": "thursday"
                },
                {
                  "type": "string",
                  "const": "friday"
                },
                {
                  "type": "string",
                  "const": "saturday"
                },
                {
                  "type": "string",
                  "const": "sunday"
                }
              ],
              "description": "Week boundary used by temporal interval breaks. Default \"monday\"."
            },
            "domain": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/DomainValue"
              },
              "minItems": 1,
              "description": "Explicit domain, PINNING the scale: [min, max] for continuous scales (numbers, or temporal strings for time); the full category list for band scales. Data outside the domain is dropped with a warning."
            },
            "nice": {
              "type": "boolean",
              "description": "Round the inferred domain to tick-friendly bounds. Default true. Ignored when `domain` is set."
            },
            "zero": {
              "type": "boolean",
              "description": "Force the domain to include zero. Bars, columns, and areas force this to true on the measure axis; set false explicitly to override. Ignored when `domain` is set."
            },
            "reverse": {
              "type": "boolean",
              "description": "Reverse the scale's output direction. Default false."
            },
            "breaks": {
              "type": "array",
              "items": {
                "anyOf": [
                  {
                    "type": "number"
                  },
                  {
                    "type": "string"
                  }
                ]
              },
              "minItems": 1,
              "description": "Explicit tick positions in data units (numbers, or ISO date strings for time scales); for binned scales these are the bin boundaries. Omit for automatic ticks. Binned scales allow at most 65 boundaries (64 bins); non-binned explicit ticks are not capped."
            },
            "labels": {
              "type": "string",
              "description": "Tick label format string. Time scales: strftime-style (\"%Y-%m\", \"%b %d\", \"%H:%M\"). Numeric scales: \",d\" (grouped integer), \".1f\" (fixed decimals), \".0%\" (percent), \"~s\" (SI prefix). Omit for automatic formatting."
            },
            "expand": {
              "$ref": "#/$defs/ScaleExpansion",
              "description": "Display-domain padding. Non-temporal continuous/binned axes default to { mult: 0.05, add: 0 }; time axes default to zero. Pinned domains still receive display expansion."
            },
            "oob": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "censor"
                },
                {
                  "type": "string",
                  "const": "squish"
                }
              ],
              "description": "Out-of-bounds policy for values outside explicit source limits, applied before stats. \"censor\" (default) drops them to missing; \"squish\" clamps them to the nearest source limit before transform."
            },
            "naValue": {
              "anyOf": [
                {
                  "type": "number"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Replacement for missing/censored positional values, resolved after OOB and before transform. A finite number substitutes; null (default) keeps them missing. The replacement is itself checked against the transform/domain rules."
            },
            "minorBreaks": {
              "type": "array",
              "items": {
                "type": "number"
              },
              "minItems": 1,
              "description": "Explicit minor gridline positions in semantic source units. Coincident major/minor values render only the major tick. Time scales use dateMinorBreaks instead."
            },
            "guide": {
              "anyOf": [
                {
                  "$ref": "#/$defs/GuideSpec"
                },
                {
                  "$ref": "#/$defs/BandAxisGuideSpec"
                }
              ]
            }
          },
          "additionalProperties": false,
          "description": "Configuration for a positional (x or y) scale."
        },
        {
          "anyOf": [
            {
              "type": "object",
              "required": [
                "type"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "binned"
                },
                "breaks": {
                  "type": "array",
                  "items": {
                    "anyOf": [
                      {
                        "type": "number"
                      },
                      {
                        "type": "string"
                      }
                    ]
                  },
                  "maxItems": 65
                }
              }
            },
            {
              "type": "object",
              "properties": {
                "type": {
                  "anyOf": [
                    {
                      "type": "string",
                      "const": "linear"
                    },
                    {
                      "type": "string",
                      "const": "log"
                    },
                    {
                      "type": "string",
                      "const": "time"
                    },
                    {
                      "type": "string",
                      "const": "band"
                    }
                  ]
                }
              }
            }
          ]
        }
      ]
    },
    "ColorScaleSpec": {
      "allOf": [
        {
          "type": "object",
          "properties": {
            "type": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "ordinal"
                },
                {
                  "type": "string",
                  "const": "sequential"
                },
                {
                  "type": "string",
                  "const": "binned"
                },
                {
                  "type": "string",
                  "const": "manual"
                },
                {
                  "type": "string",
                  "const": "identity"
                }
              ],
              "description": "Color scale family: \"ordinal\" for categories, \"sequential\" for a continuous ramp, \"binned\" for color steps, \"manual\" for an explicit domain/range mapping, or \"identity\" for validated source colors."
            },
            "transform": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "identity"
                },
                {
                  "type": "string",
                  "const": "log10"
                },
                {
                  "type": "string",
                  "const": "sqrt"
                }
              ],
              "description": "Pre-training quantitative transform for sequential/binned color values. log10/sqrt require non-temporal values; ordinal, manual, and identity families do not accept a transform."
            },
            "temporalKind": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "date"
                },
                {
                  "type": "string",
                  "const": "datetime"
                }
              ],
              "description": "Temporal precision intent for sequential/binned colors. \"date\" uses calendar labels; \"datetime\" uses instant labels."
            },
            "parse": {
              "$ref": "#/$defs/TemporalParserSpec",
              "description": "Explicit deterministic parser for temporal color/fill source values. Omit for value-driven inference."
            },
            "parseFailure": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "error"
                },
                {
                  "type": "string",
                  "const": "censor"
                }
              ],
              "description": "Explicit temporal parser failure policy: \"error\" (default) or \"censor\" with a bounded warning."
            },
            "timezone": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128,
              "description": "IANA timezone for temporal color/fill input. Default \"UTC\"."
            },
            "disambiguation": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "compatible"
                },
                {
                  "type": "string",
                  "const": "earlier"
                },
                {
                  "type": "string",
                  "const": "later"
                },
                {
                  "type": "string",
                  "const": "reject"
                }
              ]
            },
            "domain": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/DomainValue"
              },
              "minItems": 1,
              "description": "Explicit semantic domain. Manual/ordinal scales use ordered values; sequential/binned scales use [min, max]."
            },
            "domainMode": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "grow"
                },
                {
                  "type": "string",
                  "const": "data"
                }
              ],
              "description": "Ordinal domain stability: \"grow\" (default) preserves assignments across filters; \"data\" rebuilds from current data."
            },
            "breaks": {
              "type": "array",
              "items": {
                "anyOf": [
                  {
                    "type": "number"
                  },
                  {
                    "type": "string"
                  }
                ]
              },
              "minItems": 2,
              "description": "Explicit semantic reference ticks for sequential colorbars or ordered boundaries for binned colorsteps."
            },
            "range": {
              "type": "array",
              "items": {
                "type": "string",
                "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"
              },
              "minItems": 1,
              "description": "Explicit #rgb/#rrggbb colors. Manual pairs them with domain values; sequential/binned interpolate or sample them."
            },
            "scheme": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "observable10"
                },
                {
                  "type": "string",
                  "const": "ipsum"
                },
                {
                  "type": "string",
                  "const": "flexoki"
                },
                {
                  "type": "string",
                  "const": "tableau10"
                },
                {
                  "type": "string",
                  "const": "colorblind"
                },
                {
                  "type": "string",
                  "const": "stata"
                },
                {
                  "type": "string",
                  "const": "stata_s1color"
                },
                {
                  "type": "string",
                  "const": "stata_s1rcolor"
                },
                {
                  "type": "string",
                  "const": "stata_mono"
                },
                {
                  "type": "string",
                  "const": "economist"
                },
                {
                  "type": "string",
                  "const": "solarized"
                },
                {
                  "type": "string",
                  "const": "few"
                },
                {
                  "type": "string",
                  "const": "few_light"
                },
                {
                  "type": "string",
                  "const": "few_dark"
                },
                {
                  "type": "string",
                  "const": "fivethirtyeight"
                },
                {
                  "type": "string",
                  "const": "ptol"
                },
                {
                  "type": "string",
                  "const": "canva"
                },
                {
                  "type": "string",
                  "const": "wsj"
                },
                {
                  "type": "string",
                  "const": "wsj_rgby"
                },
                {
                  "type": "string",
                  "const": "wsj_red_green"
                },
                {
                  "type": "string",
                  "const": "wsj_black_green"
                },
                {
                  "type": "string",
                  "const": "wsj_dem_rep"
                },
                {
                  "type": "string",
                  "const": "tableau20"
                },
                {
                  "type": "string",
                  "const": "tableau_colorblind"
                },
                {
                  "type": "string",
                  "const": "tableau_seattle_grays"
                },
                {
                  "type": "string",
                  "const": "tableau_traffic"
                },
                {
                  "type": "string",
                  "const": "tableau_miller_stone"
                },
                {
                  "type": "string",
                  "const": "tableau_superfishel_stone"
                },
                {
                  "type": "string",
                  "const": "tableau_nuriel_stone"
                },
                {
                  "type": "string",
                  "const": "tableau_jewel_bright"
                },
                {
                  "type": "string",
                  "const": "tableau_summer"
                },
                {
                  "type": "string",
                  "const": "tableau_winter"
                },
                {
                  "type": "string",
                  "const": "tableau_green_orange_teal"
                },
                {
                  "type": "string",
                  "const": "tableau_red_blue_brown"
                },
                {
                  "type": "string",
                  "const": "tableau_purple_pink_gray"
                },
                {
                  "type": "string",
                  "const": "tableau_hue_circle"
                },
                {
                  "type": "string",
                  "const": "gdocs"
                },
                {
                  "type": "string",
                  "const": "hc"
                },
                {
                  "type": "string",
                  "const": "hc_dark"
                },
                {
                  "type": "string",
                  "const": "pander"
                },
                {
                  "type": "string",
                  "const": "calc"
                },
                {
                  "type": "string",
                  "const": "excel"
                },
                {
                  "type": "string",
                  "const": "excel_fill"
                },
                {
                  "type": "string",
                  "const": "excel_new"
                },
                {
                  "type": "string",
                  "const": "Set1"
                },
                {
                  "type": "string",
                  "const": "Set2"
                },
                {
                  "type": "string",
                  "const": "Set3"
                },
                {
                  "type": "string",
                  "const": "Dark2"
                },
                {
                  "type": "string",
                  "const": "Paired"
                },
                {
                  "type": "string",
                  "const": "Accent"
                },
                {
                  "type": "string",
                  "const": "hue"
                },
                {
                  "type": "string",
                  "const": "grey"
                },
                {
                  "type": "string",
                  "const": "gray"
                },
                {
                  "type": "string",
                  "const": "viridis"
                },
                {
                  "type": "string",
                  "const": "magma"
                },
                {
                  "type": "string",
                  "const": "plasma"
                },
                {
                  "type": "string",
                  "const": "inferno"
                },
                {
                  "type": "string",
                  "const": "cividis"
                },
                {
                  "type": "string",
                  "const": "turbo"
                },
                {
                  "type": "string",
                  "const": "Blues"
                },
                {
                  "type": "string",
                  "const": "Greens"
                },
                {
                  "type": "string",
                  "const": "Reds"
                },
                {
                  "type": "string",
                  "const": "Oranges"
                },
                {
                  "type": "string",
                  "const": "Purples"
                },
                {
                  "type": "string",
                  "const": "Greys"
                },
                {
                  "type": "string",
                  "const": "YlOrRd"
                },
                {
                  "type": "string",
                  "const": "YlGnBu"
                },
                {
                  "type": "string",
                  "const": "BuPu"
                },
                {
                  "type": "string",
                  "const": "RdYlBu"
                },
                {
                  "type": "string",
                  "const": "RdBu"
                },
                {
                  "type": "string",
                  "const": "BrBG"
                },
                {
                  "type": "string",
                  "const": "Spectral"
                },
                {
                  "type": "string",
                  "const": "PuOr"
                },
                {
                  "type": "string",
                  "const": "tableau_seq_blue_green"
                },
                {
                  "type": "string",
                  "const": "tableau_seq_blue_light"
                },
                {
                  "type": "string",
                  "const": "tableau_seq_orange_light"
                },
                {
                  "type": "string",
                  "const": "tableau_seq_blue"
                },
                {
                  "type": "string",
                  "const": "tableau_seq_orange"
                },
                {
                  "type": "string",
                  "const": "tableau_seq_green"
                },
                {
                  "type": "string",
                  "const": "tableau_seq_red"
                },
                {
                  "type": "string",
                  "const": "tableau_seq_purple"
                },
                {
                  "type": "string",
                  "const": "tableau_seq_brown"
                },
                {
                  "type": "string",
                  "const": "tableau_seq_gray"
                },
                {
                  "type": "string",
                  "const": "tableau_seq_gray_warm"
                },
                {
                  "type": "string",
                  "const": "tableau_seq_blue_teal"
                },
                {
                  "type": "string",
                  "const": "tableau_seq_orange_gold"
                },
                {
                  "type": "string",
                  "const": "tableau_seq_green_gold"
                },
                {
                  "type": "string",
                  "const": "tableau_seq_red_gold"
                },
                {
                  "type": "string",
                  "const": "tableau_div_orange_blue"
                },
                {
                  "type": "string",
                  "const": "tableau_div_red_green"
                },
                {
                  "type": "string",
                  "const": "tableau_div_green_blue"
                },
                {
                  "type": "string",
                  "const": "tableau_div_red_blue"
                },
                {
                  "type": "string",
                  "const": "tableau_div_red_black"
                },
                {
                  "type": "string",
                  "const": "tableau_div_gold_purple"
                },
                {
                  "type": "string",
                  "const": "tableau_div_red_green_gold"
                },
                {
                  "type": "string",
                  "const": "tableau_div_sunset_sunrise"
                },
                {
                  "type": "string",
                  "const": "tableau_div_orange_blue_white"
                },
                {
                  "type": "string",
                  "const": "tableau_div_red_green_white"
                },
                {
                  "type": "string",
                  "const": "tableau_div_green_blue_white"
                },
                {
                  "type": "string",
                  "const": "tableau_div_red_blue_white"
                },
                {
                  "type": "string",
                  "const": "tableau_div_red_black_white"
                },
                {
                  "type": "string",
                  "const": "tableau_div_orange_blue_light"
                },
                {
                  "type": "string",
                  "const": "tableau_div_temperature"
                }
              ],
              "description": "Named color scheme: categorical \"observable10\" (default), \"ipsum\", \"flexoki\", \"tableau10\", \"colorblind\", \"hue\", \"grey\", \"gray\", and ColorBrewer qualitative (Set1/Set2/…); or sequential family \"viridis\" (default), \"magma\", \"plasma\", \"inferno\", \"cividis\", \"turbo\", plus ColorBrewer sequential/diverging (Blues, RdYlBu, …). Sequential-family names may also be used with ordinal scales (discrete sampling). When type is omitted, the named scheme selects its ordinal or sequential scale family."
            },
            "reverse": {
              "type": "boolean",
              "description": "Reverse the output color range. Default false."
            },
            "oob": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "censor"
                },
                {
                  "type": "string",
                  "const": "squish"
                }
              ],
              "description": "Out-of-bounds policy for an explicit continuous/binned domain: \"censor\" (default) or \"squish\"."
            },
            "naValue": {
              "type": "string",
              "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$",
              "description": "Color for null/missing values. Default9."
            },
            "unknownValue": {
              "type": "string",
              "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$",
              "description": "Color for invalid, out-of-domain, or unmapped values. Default9."
            },
            "onExhaust": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "cycle"
                },
                {
                  "type": "string",
                  "const": "error"
                }
              ],
              "description": "Ordinal palette exhaustion policy: \"cycle\" (default) with a warning, or \"error\"."
            },
            "labels": {
              "type": "string",
              "description": "Guide label format: numeric (\".1f\", \",d\", \".0%\") or temporal strftime-style text."
            },
            "guide": {
              "$ref": "#/$defs/GuideSpec"
            }
          },
          "additionalProperties": false,
          "description": "Configuration for a color or fill scale."
        },
        {
          "anyOf": [
            {
              "type": "object",
              "required": [
                "type"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "binned"
                },
                "breaks": {
                  "type": "array",
                  "items": {
                    "anyOf": [
                      {
                        "type": "number"
                      },
                      {
                        "type": "string"
                      }
                    ]
                  },
                  "minItems": 2,
                  "maxItems": 65
                },
                "domainMode": {
                  "not": {}
                },
                "onExhaust": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "required": [
                "type",
                "range"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "manual"
                },
                "range": {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"
                  },
                  "minItems": 1
                },
                "transform": {
                  "not": {}
                },
                "temporalKind": {
                  "not": {}
                },
                "parse": {
                  "not": {}
                },
                "parseFailure": {
                  "not": {}
                },
                "timezone": {
                  "not": {}
                },
                "disambiguation": {
                  "not": {}
                },
                "domainMode": {
                  "not": {}
                },
                "breaks": {
                  "not": {}
                },
                "scheme": {
                  "not": {}
                },
                "reverse": {
                  "not": {}
                },
                "oob": {
                  "not": {}
                },
                "onExhaust": {
                  "not": {}
                },
                "labels": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "required": [
                "type"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "identity"
                },
                "transform": {
                  "not": {}
                },
                "temporalKind": {
                  "not": {}
                },
                "parse": {
                  "not": {}
                },
                "parseFailure": {
                  "not": {}
                },
                "timezone": {
                  "not": {}
                },
                "disambiguation": {
                  "not": {}
                },
                "domain": {
                  "not": {}
                },
                "domainMode": {
                  "not": {}
                },
                "breaks": {
                  "not": {}
                },
                "range": {
                  "not": {}
                },
                "scheme": {
                  "not": {}
                },
                "reverse": {
                  "not": {}
                },
                "oob": {
                  "not": {}
                },
                "onExhaust": {
                  "not": {}
                },
                "labels": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "required": [
                "type"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "ordinal"
                },
                "transform": {
                  "not": {}
                },
                "temporalKind": {
                  "not": {}
                },
                "parse": {
                  "not": {}
                },
                "parseFailure": {
                  "not": {}
                },
                "timezone": {
                  "not": {}
                },
                "disambiguation": {
                  "not": {}
                },
                "breaks": {
                  "not": {}
                },
                "oob": {
                  "not": {}
                },
                "labels": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "required": [
                "type"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "sequential"
                },
                "domainMode": {
                  "not": {}
                },
                "onExhaust": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "properties": {
                "type": {
                  "not": {}
                }
              }
            }
          ]
        }
      ]
    },
    "PositiveStyleScaleSpec": {
      "allOf": [
        {
          "type": "object",
          "properties": {
            "type": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "ordinal"
                },
                {
                  "type": "string",
                  "const": "sequential"
                },
                {
                  "type": "string",
                  "const": "binned"
                },
                {
                  "type": "string",
                  "const": "manual"
                },
                {
                  "type": "string",
                  "const": "identity"
                }
              ]
            },
            "temporalKind": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "date"
                },
                {
                  "type": "string",
                  "const": "datetime"
                }
              ]
            },
            "parse": {
              "$ref": "#/$defs/TemporalParserSpec"
            },
            "parseFailure": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "error"
                },
                {
                  "type": "string",
                  "const": "censor"
                }
              ]
            },
            "timezone": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            },
            "disambiguation": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "compatible"
                },
                {
                  "type": "string",
                  "const": "earlier"
                },
                {
                  "type": "string",
                  "const": "later"
                },
                {
                  "type": "string",
                  "const": "reject"
                }
              ]
            },
            "domain": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/DomainValue"
              },
              "minItems": 1
            },
            "domainMode": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "grow"
                },
                {
                  "type": "string",
                  "const": "data"
                }
              ]
            },
            "breaks": {
              "type": "array",
              "items": {
                "anyOf": [
                  {
                    "type": "number"
                  },
                  {
                    "type": "string"
                  }
                ]
              },
              "minItems": 2
            },
            "range": {
              "type": "array",
              "items": {
                "type": "number",
                "minimum": 0
              },
              "minItems": 1
            },
            "reverse": {
              "type": "boolean"
            },
            "oob": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "censor"
                },
                {
                  "type": "string",
                  "const": "squish"
                }
              ]
            },
            "naValue": {
              "type": "number",
              "minimum": 0
            },
            "unknownValue": {
              "type": "number",
              "minimum": 0
            },
            "onExhaust": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "cycle"
                },
                {
                  "type": "string",
                  "const": "error"
                }
              ]
            },
            "labels": {
              "type": "string"
            },
            "guide": {
              "$ref": "#/$defs/GuideSpec"
            },
            "sizeUnit": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "area"
                },
                {
                  "type": "string",
                  "const": "radius"
                },
                {
                  "type": "string",
                  "const": "area_zero"
                }
              ],
              "description": "Size encoding unit (size aesthetic only). \"area\" (default) interpolates by area between range endpoints; \"radius\" maps linearly to radius; \"area_zero\" maps value proportionally to area with zero→zero."
            }
          },
          "additionalProperties": false,
          "description": "Configuration for a non-negative numeric size or linewidth scale."
        },
        {
          "anyOf": [
            {
              "type": "object",
              "required": [
                "type"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "binned"
                },
                "domain": {
                  "type": "array",
                  "items": {
                    "$ref": "#/$defs/DomainValue"
                  },
                  "minItems": 2,
                  "maxItems": 2
                },
                "breaks": {
                  "type": "array",
                  "items": {
                    "anyOf": [
                      {
                        "type": "number"
                      },
                      {
                        "type": "string"
                      }
                    ]
                  },
                  "minItems": 2,
                  "maxItems": 65
                },
                "range": {
                  "type": "array",
                  "items": {
                    "type": "number",
                    "minimum": 0
                  },
                  "minItems": 2
                },
                "domainMode": {
                  "not": {}
                },
                "onExhaust": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "required": [
                "type",
                "range"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "manual"
                },
                "range": {
                  "type": "array",
                  "items": {
                    "type": "number",
                    "minimum": 0
                  },
                  "minItems": 1
                },
                "temporalKind": {
                  "not": {}
                },
                "parse": {
                  "not": {}
                },
                "parseFailure": {
                  "not": {}
                },
                "timezone": {
                  "not": {}
                },
                "disambiguation": {
                  "not": {}
                },
                "domainMode": {
                  "not": {}
                },
                "breaks": {
                  "not": {}
                },
                "reverse": {
                  "not": {}
                },
                "oob": {
                  "not": {}
                },
                "onExhaust": {
                  "not": {}
                },
                "labels": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "required": [
                "type"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "identity"
                },
                "temporalKind": {
                  "not": {}
                },
                "parse": {
                  "not": {}
                },
                "parseFailure": {
                  "not": {}
                },
                "timezone": {
                  "not": {}
                },
                "disambiguation": {
                  "not": {}
                },
                "domain": {
                  "not": {}
                },
                "domainMode": {
                  "not": {}
                },
                "breaks": {
                  "not": {}
                },
                "range": {
                  "not": {}
                },
                "reverse": {
                  "not": {}
                },
                "oob": {
                  "not": {}
                },
                "onExhaust": {
                  "not": {}
                },
                "labels": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "required": [
                "type"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "ordinal"
                },
                "temporalKind": {
                  "not": {}
                },
                "parse": {
                  "not": {}
                },
                "parseFailure": {
                  "not": {}
                },
                "timezone": {
                  "not": {}
                },
                "disambiguation": {
                  "not": {}
                },
                "breaks": {
                  "not": {}
                },
                "oob": {
                  "not": {}
                },
                "labels": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "required": [
                "type"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "sequential"
                },
                "domain": {
                  "type": "array",
                  "items": {
                    "$ref": "#/$defs/DomainValue"
                  },
                  "minItems": 2,
                  "maxItems": 2
                },
                "range": {
                  "type": "array",
                  "items": {
                    "type": "number",
                    "minimum": 0
                  },
                  "minItems": 2
                },
                "domainMode": {
                  "not": {}
                },
                "onExhaust": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "properties": {
                "type": {
                  "not": {}
                }
              }
            }
          ]
        }
      ]
    },
    "AlphaScaleSpec": {
      "allOf": [
        {
          "type": "object",
          "properties": {
            "type": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "ordinal"
                },
                {
                  "type": "string",
                  "const": "sequential"
                },
                {
                  "type": "string",
                  "const": "binned"
                },
                {
                  "type": "string",
                  "const": "manual"
                },
                {
                  "type": "string",
                  "const": "identity"
                }
              ]
            },
            "temporalKind": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "date"
                },
                {
                  "type": "string",
                  "const": "datetime"
                }
              ]
            },
            "parse": {
              "$ref": "#/$defs/TemporalParserSpec"
            },
            "parseFailure": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "error"
                },
                {
                  "type": "string",
                  "const": "censor"
                }
              ]
            },
            "timezone": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            },
            "disambiguation": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "compatible"
                },
                {
                  "type": "string",
                  "const": "earlier"
                },
                {
                  "type": "string",
                  "const": "later"
                },
                {
                  "type": "string",
                  "const": "reject"
                }
              ]
            },
            "domain": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/DomainValue"
              },
              "minItems": 1
            },
            "domainMode": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "grow"
                },
                {
                  "type": "string",
                  "const": "data"
                }
              ]
            },
            "breaks": {
              "type": "array",
              "items": {
                "anyOf": [
                  {
                    "type": "number"
                  },
                  {
                    "type": "string"
                  }
                ]
              },
              "minItems": 2
            },
            "range": {
              "type": "array",
              "items": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              },
              "minItems": 1
            },
            "reverse": {
              "type": "boolean"
            },
            "oob": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "censor"
                },
                {
                  "type": "string",
                  "const": "squish"
                }
              ]
            },
            "naValue": {
              "type": "number",
              "minimum": 0,
              "maximum": 1
            },
            "unknownValue": {
              "type": "number",
              "minimum": 0,
              "maximum": 1
            },
            "onExhaust": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "cycle"
                },
                {
                  "type": "string",
                  "const": "error"
                }
              ]
            },
            "labels": {
              "type": "string"
            },
            "guide": {
              "$ref": "#/$defs/GuideSpec"
            }
          },
          "additionalProperties": false,
          "description": "Configuration for an opacity scale constrained to [0, 1]."
        },
        {
          "anyOf": [
            {
              "type": "object",
              "required": [
                "type"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "binned"
                },
                "domain": {
                  "type": "array",
                  "items": {
                    "$ref": "#/$defs/DomainValue"
                  },
                  "minItems": 2,
                  "maxItems": 2
                },
                "breaks": {
                  "type": "array",
                  "items": {
                    "anyOf": [
                      {
                        "type": "number"
                      },
                      {
                        "type": "string"
                      }
                    ]
                  },
                  "minItems": 2,
                  "maxItems": 65
                },
                "range": {
                  "type": "array",
                  "items": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1
                  },
                  "minItems": 2
                },
                "domainMode": {
                  "not": {}
                },
                "onExhaust": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "required": [
                "type",
                "range"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "manual"
                },
                "range": {
                  "type": "array",
                  "items": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1
                  },
                  "minItems": 1
                },
                "temporalKind": {
                  "not": {}
                },
                "parse": {
                  "not": {}
                },
                "parseFailure": {
                  "not": {}
                },
                "timezone": {
                  "not": {}
                },
                "disambiguation": {
                  "not": {}
                },
                "domainMode": {
                  "not": {}
                },
                "breaks": {
                  "not": {}
                },
                "reverse": {
                  "not": {}
                },
                "oob": {
                  "not": {}
                },
                "onExhaust": {
                  "not": {}
                },
                "labels": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "required": [
                "type"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "identity"
                },
                "temporalKind": {
                  "not": {}
                },
                "parse": {
                  "not": {}
                },
                "parseFailure": {
                  "not": {}
                },
                "timezone": {
                  "not": {}
                },
                "disambiguation": {
                  "not": {}
                },
                "domain": {
                  "not": {}
                },
                "domainMode": {
                  "not": {}
                },
                "breaks": {
                  "not": {}
                },
                "range": {
                  "not": {}
                },
                "reverse": {
                  "not": {}
                },
                "oob": {
                  "not": {}
                },
                "onExhaust": {
                  "not": {}
                },
                "labels": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "required": [
                "type"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "ordinal"
                },
                "temporalKind": {
                  "not": {}
                },
                "parse": {
                  "not": {}
                },
                "parseFailure": {
                  "not": {}
                },
                "timezone": {
                  "not": {}
                },
                "disambiguation": {
                  "not": {}
                },
                "breaks": {
                  "not": {}
                },
                "oob": {
                  "not": {}
                },
                "labels": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "required": [
                "type"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "sequential"
                },
                "domain": {
                  "type": "array",
                  "items": {
                    "$ref": "#/$defs/DomainValue"
                  },
                  "minItems": 2,
                  "maxItems": 2
                },
                "range": {
                  "type": "array",
                  "items": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1
                  },
                  "minItems": 2
                },
                "domainMode": {
                  "not": {}
                },
                "onExhaust": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "properties": {
                "type": {
                  "not": {}
                }
              }
            }
          ]
        }
      ]
    },
    "ShapeScaleSpec": {
      "allOf": [
        {
          "type": "object",
          "properties": {
            "type": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "ordinal"
                },
                {
                  "type": "string",
                  "const": "binned"
                },
                {
                  "type": "string",
                  "const": "manual"
                },
                {
                  "type": "string",
                  "const": "identity"
                }
              ]
            },
            "domain": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/DomainValue"
              },
              "minItems": 1
            },
            "domainMode": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "grow"
                },
                {
                  "type": "string",
                  "const": "data"
                }
              ]
            },
            "breaks": {
              "type": "array",
              "items": {
                "type": "number"
              },
              "minItems": 2
            },
            "range": {
              "type": "array",
              "items": {
                "anyOf": [
                  {
                    "type": "string",
                    "const": "circle"
                  },
                  {
                    "type": "string",
                    "const": "triangle"
                  },
                  {
                    "type": "string",
                    "const": "square"
                  },
                  {
                    "type": "string",
                    "const": "diamond"
                  },
                  {
                    "type": "string",
                    "const": "plus"
                  },
                  {
                    "type": "string",
                    "const": "cross"
                  }
                ]
              },
              "minItems": 1
            },
            "reverse": {
              "type": "boolean"
            },
            "naValue": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "circle"
                },
                {
                  "type": "string",
                  "const": "triangle"
                },
                {
                  "type": "string",
                  "const": "square"
                },
                {
                  "type": "string",
                  "const": "diamond"
                },
                {
                  "type": "string",
                  "const": "plus"
                },
                {
                  "type": "string",
                  "const": "cross"
                }
              ]
            },
            "unknownValue": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "circle"
                },
                {
                  "type": "string",
                  "const": "triangle"
                },
                {
                  "type": "string",
                  "const": "square"
                },
                {
                  "type": "string",
                  "const": "diamond"
                },
                {
                  "type": "string",
                  "const": "plus"
                },
                {
                  "type": "string",
                  "const": "cross"
                }
              ]
            },
            "onExhaust": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "cycle"
                },
                {
                  "type": "string",
                  "const": "error"
                }
              ]
            },
            "labels": {
              "type": "string"
            },
            "guide": {
              "$ref": "#/$defs/GuideSpec"
            }
          },
          "additionalProperties": false,
          "description": "Configuration for a finite point-shape scale."
        },
        {
          "anyOf": [
            {
              "type": "object",
              "required": [
                "type"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "binned"
                },
                "domain": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  },
                  "minItems": 2,
                  "maxItems": 2
                },
                "breaks": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  },
                  "minItems": 2,
                  "maxItems": 65
                },
                "domainMode": {
                  "not": {}
                },
                "onExhaust": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "required": [
                "type",
                "range"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "manual"
                },
                "range": {
                  "type": "array",
                  "items": {
                    "anyOf": [
                      {
                        "type": "string",
                        "const": "circle"
                      },
                      {
                        "type": "string",
                        "const": "triangle"
                      },
                      {
                        "type": "string",
                        "const": "square"
                      },
                      {
                        "type": "string",
                        "const": "diamond"
                      },
                      {
                        "type": "string",
                        "const": "plus"
                      },
                      {
                        "type": "string",
                        "const": "cross"
                      }
                    ]
                  },
                  "minItems": 1
                },
                "domainMode": {
                  "not": {}
                },
                "breaks": {
                  "not": {}
                },
                "reverse": {
                  "not": {}
                },
                "onExhaust": {
                  "not": {}
                },
                "labels": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "required": [
                "type"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "identity"
                },
                "domain": {
                  "not": {}
                },
                "domainMode": {
                  "not": {}
                },
                "breaks": {
                  "not": {}
                },
                "range": {
                  "not": {}
                },
                "reverse": {
                  "not": {}
                },
                "onExhaust": {
                  "not": {}
                },
                "labels": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "required": [
                "type"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "ordinal"
                },
                "breaks": {
                  "not": {}
                },
                "labels": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "properties": {
                "type": {
                  "not": {}
                }
              }
            }
          ]
        }
      ]
    },
    "LinetypeScaleSpec": {
      "allOf": [
        {
          "type": "object",
          "properties": {
            "type": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "ordinal"
                },
                {
                  "type": "string",
                  "const": "binned"
                },
                {
                  "type": "string",
                  "const": "manual"
                },
                {
                  "type": "string",
                  "const": "identity"
                }
              ]
            },
            "domain": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/DomainValue"
              },
              "minItems": 1
            },
            "domainMode": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "grow"
                },
                {
                  "type": "string",
                  "const": "data"
                }
              ]
            },
            "breaks": {
              "type": "array",
              "items": {
                "type": "number"
              },
              "minItems": 2
            },
            "range": {
              "type": "array",
              "items": {
                "anyOf": [
                  {
                    "type": "string",
                    "const": "solid"
                  },
                  {
                    "type": "string",
                    "const": "dashed"
                  },
                  {
                    "type": "string",
                    "const": "dotted"
                  },
                  {
                    "type": "string",
                    "const": "dotdash"
                  },
                  {
                    "type": "string",
                    "const": "longdash"
                  },
                  {
                    "type": "string",
                    "const": "twodash"
                  }
                ]
              },
              "minItems": 1
            },
            "reverse": {
              "type": "boolean"
            },
            "naValue": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "solid"
                },
                {
                  "type": "string",
                  "const": "dashed"
                },
                {
                  "type": "string",
                  "const": "dotted"
                },
                {
                  "type": "string",
                  "const": "dotdash"
                },
                {
                  "type": "string",
                  "const": "longdash"
                },
                {
                  "type": "string",
                  "const": "twodash"
                }
              ]
            },
            "unknownValue": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "solid"
                },
                {
                  "type": "string",
                  "const": "dashed"
                },
                {
                  "type": "string",
                  "const": "dotted"
                },
                {
                  "type": "string",
                  "const": "dotdash"
                },
                {
                  "type": "string",
                  "const": "longdash"
                },
                {
                  "type": "string",
                  "const": "twodash"
                }
              ]
            },
            "onExhaust": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "cycle"
                },
                {
                  "type": "string",
                  "const": "error"
                }
              ]
            },
            "labels": {
              "type": "string"
            },
            "guide": {
              "$ref": "#/$defs/GuideSpec"
            }
          },
          "additionalProperties": false,
          "description": "Configuration for a finite line-pattern scale."
        },
        {
          "anyOf": [
            {
              "type": "object",
              "required": [
                "type"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "binned"
                },
                "domain": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  },
                  "minItems": 2,
                  "maxItems": 2
                },
                "breaks": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  },
                  "minItems": 2,
                  "maxItems": 65
                },
                "domainMode": {
                  "not": {}
                },
                "onExhaust": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "required": [
                "type",
                "range"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "manual"
                },
                "range": {
                  "type": "array",
                  "items": {
                    "anyOf": [
                      {
                        "type": "string",
                        "const": "solid"
                      },
                      {
                        "type": "string",
                        "const": "dashed"
                      },
                      {
                        "type": "string",
                        "const": "dotted"
                      },
                      {
                        "type": "string",
                        "const": "dotdash"
                      },
                      {
                        "type": "string",
                        "const": "longdash"
                      },
                      {
                        "type": "string",
                        "const": "twodash"
                      }
                    ]
                  },
                  "minItems": 1
                },
                "domainMode": {
                  "not": {}
                },
                "breaks": {
                  "not": {}
                },
                "reverse": {
                  "not": {}
                },
                "onExhaust": {
                  "not": {}
                },
                "labels": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "required": [
                "type"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "identity"
                },
                "domain": {
                  "not": {}
                },
                "domainMode": {
                  "not": {}
                },
                "breaks": {
                  "not": {}
                },
                "range": {
                  "not": {}
                },
                "reverse": {
                  "not": {}
                },
                "onExhaust": {
                  "not": {}
                },
                "labels": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "required": [
                "type"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "ordinal"
                },
                "breaks": {
                  "not": {}
                },
                "labels": {
                  "not": {}
                }
              }
            },
            {
              "type": "object",
              "properties": {
                "type": {
                  "not": {}
                }
              }
            }
          ]
        }
      ]
    },
    "Scales": {
      "type": "object",
      "properties": {
        "x": {
          "$ref": "#/$defs/PositionScaleSpec"
        },
        "y": {
          "$ref": "#/$defs/PositionScaleSpec"
        },
        "color": {
          "$ref": "#/$defs/ColorScaleSpec"
        },
        "fill": {
          "$ref": "#/$defs/ColorScaleSpec"
        },
        "size": {
          "$ref": "#/$defs/PositiveStyleScaleSpec"
        },
        "linewidth": {
          "$ref": "#/$defs/PositiveStyleScaleSpec"
        },
        "alpha": {
          "$ref": "#/$defs/AlphaScaleSpec"
        },
        "shape": {
          "$ref": "#/$defs/ShapeScaleSpec"
        },
        "linetype": {
          "$ref": "#/$defs/LinetypeScaleSpec"
        }
      },
      "additionalProperties": false,
      "description": "Per-scale configuration, keyed by aesthetic. Omitted scales use inference (type from field data, domain from data extent)."
    },
    "GuideThemeSpec": {
      "type": "object",
      "properties": {
        "titleSize": {
          "type": "number",
          "minimum": 8,
          "maximum": 32
        },
        "labelSize": {
          "type": "number",
          "minimum": 8,
          "maximum": 24
        },
        "keyGap": {
          "type": "number",
          "minimum": 0,
          "maximum": 32
        },
        "rowGap": {
          "type": "number",
          "minimum": 0,
          "maximum": 32
        },
        "blockGap": {
          "type": "number",
          "minimum": 0,
          "maximum": 64
        },
        "colorbarThickness": {
          "type": "number",
          "minimum": 4,
          "maximum": 48
        },
        "colorbarLength": {
          "type": "number",
          "minimum": 48,
          "maximum": 512
        }
      },
      "additionalProperties": false,
      "description": "Bounded presentation overrides for one guide block."
    },
    "BandAxisGuideSpec": {
      "type": "object",
      "properties": {
        "mode": {
          "anyOf": [
            {
              "type": "string",
              "const": "auto"
            },
            {
              "type": "string",
              "const": "single"
            },
            {
              "type": "string",
              "const": "wrap"
            },
            {
              "type": "string",
              "const": "rotate"
            },
            {
              "type": "string",
              "const": "off"
            }
          ],
          "description": "Band axis label layout: \"auto\", \"single\", \"wrap\", \"rotate\", or \"off\"."
        },
        "angle": {
          "type": "number",
          "description": "Rotation in degrees when mode is \"rotate\"."
        },
        "wrap": {
          "type": "number",
          "minimum": 1,
          "maximum": 8,
          "description": "Maximum wrapped lines when mode is \"wrap\"."
        }
      },
      "additionalProperties": false,
      "description": "Scale-local band-axis label layout override retained independently from guide appearance."
    },
    "AxisGuideSpec": {
      "type": "object",
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "type": "string",
          "const": "axis"
        },
        "title": {
          "type": "string",
          "maxLength": 256
        },
        "showTicks": {
          "type": "boolean"
        },
        "showLabels": {
          "type": "boolean"
        },
        "collision": {
          "anyOf": [
            {
              "type": "string",
              "const": "auto"
            },
            {
              "type": "string",
              "const": "preserve"
            },
            {
              "type": "string",
              "const": "ellipsis"
            }
          ]
        },
        "theme": {
          "$ref": "#/$defs/GuideThemeSpec"
        }
      },
      "additionalProperties": false
    },
    "LegendGuideSpec": {
      "type": "object",
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "type": "string",
          "const": "legend"
        },
        "title": {
          "type": "string",
          "maxLength": 256
        },
        "order": {
          "type": "integer",
          "minimum": -1024,
          "maximum": 1024
        },
        "position": {
          "anyOf": [
            {
              "type": "string",
              "const": "auto"
            },
            {
              "type": "string",
              "const": "right"
            },
            {
              "type": "string",
              "const": "bottom"
            }
          ]
        },
        "direction": {
          "anyOf": [
            {
              "type": "string",
              "const": "auto"
            },
            {
              "type": "string",
              "const": "vertical"
            },
            {
              "type": "string",
              "const": "horizontal"
            }
          ]
        },
        "keySize": {
          "type": "number",
          "minimum": 4,
          "maximum": 48
        },
        "collision": {
          "anyOf": [
            {
              "type": "string",
              "const": "ellipsis"
            },
            {
              "type": "string",
              "const": "wrap"
            },
            {
              "type": "string",
              "const": "error"
            }
          ]
        },
        "force": {
          "type": "boolean"
        },
        "theme": {
          "$ref": "#/$defs/GuideThemeSpec"
        }
      },
      "additionalProperties": false
    },
    "ColorbarGuideSpec": {
      "type": "object",
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "type": "string",
          "const": "colorbar"
        },
        "title": {
          "type": "string",
          "maxLength": 256
        },
        "order": {
          "type": "integer",
          "minimum": -1024,
          "maximum": 1024
        },
        "position": {
          "anyOf": [
            {
              "type": "string",
              "const": "auto"
            },
            {
              "type": "string",
              "const": "right"
            },
            {
              "type": "string",
              "const": "bottom"
            }
          ]
        },
        "direction": {
          "anyOf": [
            {
              "type": "string",
              "const": "auto"
            },
            {
              "type": "string",
              "const": "vertical"
            },
            {
              "type": "string",
              "const": "horizontal"
            }
          ]
        },
        "showTicks": {
          "type": "boolean"
        },
        "showLabels": {
          "type": "boolean"
        },
        "collision": {
          "anyOf": [
            {
              "type": "string",
              "const": "ellipsis"
            },
            {
              "type": "string",
              "const": "error"
            }
          ]
        },
        "force": {
          "type": "boolean"
        },
        "theme": {
          "$ref": "#/$defs/GuideThemeSpec"
        }
      },
      "additionalProperties": false
    },
    "ColorstepsGuideSpec": {
      "type": "object",
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "type": "string",
          "const": "colorsteps"
        },
        "title": {
          "type": "string",
          "maxLength": 256
        },
        "order": {
          "type": "integer",
          "minimum": -1024,
          "maximum": 1024
        },
        "position": {
          "anyOf": [
            {
              "type": "string",
              "const": "auto"
            },
            {
              "type": "string",
              "const": "right"
            },
            {
              "type": "string",
              "const": "bottom"
            }
          ]
        },
        "direction": {
          "anyOf": [
            {
              "type": "string",
              "const": "auto"
            },
            {
              "type": "string",
              "const": "vertical"
            },
            {
              "type": "string",
              "const": "horizontal"
            }
          ]
        },
        "showLabels": {
          "type": "boolean"
        },
        "collision": {
          "anyOf": [
            {
              "type": "string",
              "const": "ellipsis"
            },
            {
              "type": "string",
              "const": "error"
            }
          ]
        },
        "force": {
          "type": "boolean"
        },
        "theme": {
          "$ref": "#/$defs/GuideThemeSpec"
        }
      },
      "additionalProperties": false
    },
    "NoneGuideSpec": {
      "type": "object",
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "type": "string",
          "const": "none"
        }
      },
      "additionalProperties": false
    },
    "GuideSpec": {
      "anyOf": [
        {
          "$ref": "#/$defs/AxisGuideSpec"
        },
        {
          "$ref": "#/$defs/LegendGuideSpec"
        },
        {
          "$ref": "#/$defs/ColorbarGuideSpec"
        },
        {
          "$ref": "#/$defs/ColorstepsGuideSpec"
        },
        {
          "$ref": "#/$defs/NoneGuideSpec"
        }
      ]
    },
    "GuidesSpec": {
      "type": "object",
      "properties": {
        "x": {
          "$ref": "#/$defs/GuideSpec"
        },
        "y": {
          "$ref": "#/$defs/GuideSpec"
        },
        "color": {
          "$ref": "#/$defs/GuideSpec"
        },
        "fill": {
          "$ref": "#/$defs/GuideSpec"
        },
        "size": {
          "$ref": "#/$defs/GuideSpec"
        },
        "linewidth": {
          "$ref": "#/$defs/GuideSpec"
        },
        "alpha": {
          "$ref": "#/$defs/GuideSpec"
        },
        "shape": {
          "$ref": "#/$defs/GuideSpec"
        },
        "linetype": {
          "$ref": "#/$defs/GuideSpec"
        }
      },
      "additionalProperties": false,
      "description": "Appearance-only guide configuration keyed by aesthetic."
    },
    "LegendSpec": {
      "type": "object",
      "properties": {
        "order": {
          "anyOf": [
            {
              "type": "string",
              "const": "stable-domain"
            },
            {
              "type": "string",
              "const": "present-first-seen"
            },
            {
              "type": "string",
              "const": "sorted"
            }
          ],
          "description": "Order of discrete legend entries: \"stable-domain\" (default — stored assignment order, stable across data changes), \"present-first-seen\" (first occurrence in the current data), \"sorted\" (alphabetical). Ordering NEVER changes color assignments."
        }
      },
      "additionalProperties": false,
      "description": "Legend options. Legends style only through the theme."
    },
    "ThemeName": {
      "anyOf": [
        {
          "type": "string",
          "const": "default"
        },
        {
          "type": "string",
          "const": "light"
        },
        {
          "type": "string",
          "const": "dark"
        },
        {
          "type": "string",
          "const": "minimal"
        },
        {
          "type": "string",
          "const": "ggplot2"
        },
        {
          "type": "string",
          "const": "classic"
        },
        {
          "type": "string",
          "const": "bw"
        },
        {
          "type": "string",
          "const": "hrbr"
        },
        {
          "type": "string",
          "const": "few"
        },
        {
          "type": "string",
          "const": "clean"
        },
        {
          "type": "string",
          "const": "fivethirtyeight"
        },
        {
          "type": "string",
          "const": "economist"
        },
        {
          "type": "string",
          "const": "tufte"
        },
        {
          "type": "string",
          "const": "linedraw"
        },
        {
          "type": "string",
          "const": "void"
        },
        {
          "type": "string",
          "const": "stata"
        },
        {
          "type": "string",
          "const": "stata_s1color"
        },
        {
          "type": "string",
          "const": "stata_mono"
        },
        {
          "type": "string",
          "const": "solarized"
        },
        {
          "type": "string",
          "const": "solarizeddark"
        },
        {
          "type": "string",
          "const": "economist_white"
        },
        {
          "type": "string",
          "const": "solarized_2"
        },
        {
          "type": "string",
          "const": "solarized_2dark"
        },
        {
          "type": "string",
          "const": "wsj"
        },
        {
          "type": "string",
          "const": "gdocs"
        },
        {
          "type": "string",
          "const": "hc"
        },
        {
          "type": "string",
          "const": "hcdark"
        },
        {
          "type": "string",
          "const": "pander"
        },
        {
          "type": "string",
          "const": "calc"
        },
        {
          "type": "string",
          "const": "excel"
        },
        {
          "type": "string",
          "const": "excel_new"
        },
        {
          "type": "string",
          "const": "base"
        },
        {
          "type": "string",
          "const": "igray"
        },
        {
          "type": "string",
          "const": "map"
        },
        {
          "type": "string",
          "const": "solid"
        },
        {
          "type": "string",
          "const": "grey"
        },
        {
          "type": "string",
          "const": "gray"
        },
        {
          "type": "string",
          "const": "test"
        }
      ],
      "description": "A registered theme name: \"default\", \"light\", \"dark\", \"minimal\", \"ggplot2\", \"classic\", \"bw\", \"hrbr\", \"few\", \"clean\", \"fivethirtyeight\", \"economist\", \"tufte\", \"linedraw\", \"void\", \"stata\", \"stata_s1color\", \"stata_mono\", \"solarized\", \"solarizeddark\", \"economist_white\", \"solarized_2\", \"solarized_2dark\", \"wsj\", \"gdocs\", \"hc\", \"hcdark\", \"pander\", \"calc\", \"excel\", \"excel_new\", \"base\", \"igray\", \"map\", \"solid\", \"grey\", \"gray\", \"test\"."
    },
    "ThemeSpec": {
      "type": "object",
      "properties": {
        "name": {
          "$ref": "#/$defs/ThemeName",
          "description": "Base theme to override. Default \"default\"."
        },
        "ink": {
          "type": "string",
          "description": "Foreground role (CSS color): axis lines, tick labels, titles, unmapped line/point/text marks."
        },
        "paper": {
          "type": "string",
          "description": "Background role (CSS color) painted behind the plot. \"none\" for transparent."
        },
        "accent": {
          "type": "string",
          "description": "Accent role (CSS color): default fill for unmapped bars, columns, and areas."
        },
        "grid": {
          "type": "string",
          "description": "Panel grid line color (CSS color)."
        },
        "panel": {
          "type": "string",
          "description": "Panel background color (CSS color)."
        },
        "letterboxFill": {
          "type": "string",
          "description": "Fixed-aspect gutter color (CSS color). Defaults to the resolved paper role."
        },
        "axisText": {
          "type": "string",
          "description": "Axis tick-label color (CSS color)."
        },
        "axisLine": {
          "type": "string",
          "description": "Axis-line color (CSS color)."
        },
        "tickColor": {
          "type": "string",
          "description": "Axis-tick color (CSS color)."
        },
        "panelBorder": {
          "type": "string",
          "description": "Panel-border color (CSS color)."
        },
        "interactionInk": {
          "type": "string",
          "description": "Primary interaction-control and overlay ink (CSS color)."
        },
        "interactionMuted": {
          "type": "number",
          "exclusiveMinimum": 0,
          "exclusiveMaximum": 1,
          "description": "Opacity for marks de-emphasized by an interaction."
        },
        "focusRing": {
          "type": "string",
          "description": "Focus-ring color (CSS color)."
        },
        "crosshair": {
          "type": "string",
          "description": "Crosshair-guide color (CSS color)."
        },
        "selectionFill": {
          "type": "string",
          "description": "Interval-selection fill (CSS color, normally translucent)."
        },
        "selectionStroke": {
          "type": "string",
          "description": "Selection and zoom-target stroke (CSS color)."
        },
        "tooltipPaper": {
          "type": "string",
          "description": "Opaque tooltip surface (CSS color)."
        },
        "tooltipInk": {
          "type": "string",
          "description": "Tooltip foreground (CSS color)."
        },
        "tooltipBorder": {
          "type": "string",
          "description": "Tooltip keyline (CSS color)."
        },
        "toolActive": {
          "type": "string",
          "description": "Active-tool text and underline (CSS color)."
        },
        "fontFamily": {
          "type": "string",
          "description": "Chart font-family stack."
        },
        "fontSize": {
          "type": "number",
          "minimum": 1,
          "description": "Base and tick-label font size in px."
        },
        "axisTextSize": {
          "type": "number",
          "minimum": 1
        },
        "fontWeight": {
          "type": "number",
          "minimum": 1,
          "maximum": 1000
        },
        "titleSize": {
          "type": "number",
          "minimum": 1
        },
        "titleWeight": {
          "type": "number",
          "minimum": 1,
          "maximum": 1000
        },
        "subtitleSize": {
          "type": "number",
          "minimum": 1
        },
        "subtitleWeight": {
          "type": "number",
          "minimum": 1,
          "maximum": 1000
        },
        "axisTitleSize": {
          "type": "number",
          "minimum": 1
        },
        "axisTitleWeight": {
          "type": "number",
          "minimum": 1,
          "maximum": 1000
        },
        "guideTitleSize": {
          "type": "number",
          "minimum": 8,
          "maximum": 32
        },
        "legendKeySize": {
          "type": "number",
          "minimum": 4,
          "maximum": 48
        },
        "legendKeyGap": {
          "type": "number",
          "minimum": 0,
          "maximum": 32
        },
        "legendRowGap": {
          "type": "number",
          "minimum": 0,
          "maximum": 32
        },
        "guideBlockGap": {
          "type": "number",
          "minimum": 0,
          "maximum": 64
        },
        "colorbarThickness": {
          "type": "number",
          "minimum": 4,
          "maximum": 48
        },
        "colorbarLengthMin": {
          "type": "number",
          "minimum": 48,
          "maximum": 512
        },
        "captionSize": {
          "type": "number",
          "minimum": 1
        },
        "stripSize": {
          "type": "number",
          "minimum": 1
        },
        "stripWeight": {
          "type": "number",
          "minimum": 1,
          "maximum": 1000
        },
        "axisLineWidth": {
          "type": "number",
          "minimum": 0
        },
        "tickWidth": {
          "type": "number",
          "minimum": 0
        },
        "tickLength": {
          "type": "number",
          "minimum": 0
        },
        "gridWidth": {
          "type": "number",
          "minimum": 0
        },
        "panelBorderWidth": {
          "type": "number",
          "minimum": 0
        },
        "gridDasharray": {
          "type": "string",
          "description": "SVG stroke-dasharray for major grid lines."
        },
        "axisLineX": {
          "type": "boolean"
        },
        "axisLineY": {
          "type": "boolean"
        },
        "ticksX": {
          "type": "boolean"
        },
        "ticksY": {
          "type": "boolean"
        },
        "labelsX": {
          "type": "boolean",
          "description": "When false, suppress x-axis tick labels (theme_void)."
        },
        "labelsY": {
          "type": "boolean",
          "description": "When false, suppress y-axis tick labels (theme_void)."
        },
        "gridX": {
          "type": "boolean"
        },
        "gridY": {
          "type": "boolean"
        },
        "showPanelBorder": {
          "type": "boolean"
        }
      },
      "additionalProperties": false,
      "description": "A theme object: a named base plus role overrides. Roles feed geom defaults (ink/paper/accent); every color rides a --gg-* CSS custom property so hosts can restyle without a re-render."
    },
    "Labs": {
      "type": "object",
      "properties": {
        "title": {
          "type": "string",
          "description": "Plot title."
        },
        "subtitle": {
          "type": "string",
          "description": "Plot subtitle, under the title."
        },
        "caption": {
          "type": "string",
          "description": "Small caption under the plot."
        },
        "x": {
          "type": "string",
          "description": "X axis title. Defaults to a humanized form of the mapped field name (sentence case)."
        },
        "y": {
          "type": "string",
          "description": "Y axis title. Defaults to a humanized form of the mapped field name (sentence case)."
        },
        "color": {
          "type": "string",
          "description": "Color legend title. Defaults to a humanized form of the mapped field name (sentence case)."
        },
        "fill": {
          "type": "string",
          "description": "Fill legend title. Defaults to a humanized form of the mapped field name (sentence case)."
        },
        "size": {
          "type": "string",
          "description": "Size legend title. Defaults to a humanized form of the mapped field name (sentence case)."
        },
        "linewidth": {
          "type": "string",
          "description": "Linewidth legend title. Defaults to a humanized form of the mapped field name (sentence case)."
        },
        "alpha": {
          "type": "string",
          "description": "Alpha legend title. Defaults to a humanized form of the mapped field name (sentence case)."
        },
        "shape": {
          "type": "string",
          "description": "Shape legend title. Defaults to a humanized form of the mapped field name (sentence case)."
        },
        "linetype": {
          "type": "string",
          "description": "Linetype legend title. Defaults to a humanized form of the mapped field name (sentence case)."
        }
      },
      "additionalProperties": false,
      "description": "Human-readable labels: titles, axis titles, legend titles, caption."
    },
    "FacetScales": {
      "anyOf": [
        {
          "type": "string",
          "const": "fixed"
        },
        {
          "type": "string",
          "const": "free"
        },
        {
          "type": "string",
          "const": "free_x"
        },
        {
          "type": "string",
          "const": "free_y"
        }
      ],
      "description": "How positional scales behave across facet panels: \"fixed\" (default — all panels share both scales, trained on the union of panel data), \"free\" (both positional scales train per panel), \"free_x\" (only x is per-panel), \"free_y\" (only y is per-panel). Discrete color/fill assignments are ALWAYS global (one legend), regardless of this setting."
    },
    "FacetFieldRef": {
      "type": "object",
      "required": [
        "field"
      ],
      "properties": {
        "field": {
          "type": "string",
          "description": "Name of the data column that partitions facet panels."
        },
        "levels": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/DomainValue"
          },
          "minItems": 1,
          "description": "Closed explicit panel order for this facet field. When set, panels appear in this order (including empty panels for levels absent from data). Values observed in data but omitted from levels are dropped from all panels and diagnosed. Omit for the default ascending sort of observed values."
        },
        "labels": {
          "type": "object",
          "additionalProperties": {
            "type": "string"
          },
          "description": "Display-label map for authored facet values (JSON object). Keys are string forms of the semantic values (\"west\", \"1\", \"true\", \"null\"); values are human-readable strip/accessibility text. Labels never change panel IDs or semantic facet identity. Omit to use bandKey(value) as the strip text."
        }
      },
      "additionalProperties": false,
      "description": "Facet field reference with optional closed order and display labels. Example: {\"field\": \"region\", \"levels\": [\"west\", \"east\"], \"labels\": {\"west\": \"West Coast\"}}. Bare strings are NOT valid here — normalize() expands \"region\" to {\"field\": \"region\"}."
    },
    "FacetStripSpec": {
      "type": "object",
      "properties": {
        "position": {
          "anyOf": [
            {
              "type": "string",
              "const": "top"
            },
            {
              "type": "string",
              "const": "bottom"
            },
            {
              "type": "string",
              "const": "left"
            },
            {
              "type": "string",
              "const": "right"
            }
          ],
          "description": "Where facet strip bands are reserved and drawn: \"top\" (default), \"bottom\", \"left\", or \"right\". Left/right strips participate in layout measurement rather than overlaying the panel."
        },
        "show": {
          "type": "boolean",
          "description": "Whether to reserve and draw strip bands (default true). Set false when direct labels are authored elsewhere; panel identity and authored display labels remain available to accessibility and interaction consumers."
        }
      },
      "additionalProperties": false,
      "description": "Facet strip chrome: position and visibility. Defaults: position \"top\", show true. Example: {\"position\": \"left\"} or {\"show\": false}."
    },
    "FacetSpec": {
      "type": "object",
      "properties": {
        "wrap": {
          "$ref": "#/$defs/FacetFieldRef",
          "description": "Facet WRAP form: partition rows by this data field's distinct values, one panel per value, wrapped into a grid ncol wide. Mutually exclusive with rows/cols. Optional levels/labels control order and strip text."
        },
        "rows": {
          "$ref": "#/$defs/FacetFieldRef",
          "description": "Facet GRID form: the field whose distinct values become grid rows. Combine with cols; mutually exclusive with wrap. Optional levels/labels control order and strip text."
        },
        "cols": {
          "$ref": "#/$defs/FacetFieldRef",
          "description": "Facet GRID form: the field whose distinct values become grid columns. Combine with rows; mutually exclusive with wrap. Optional levels/labels control order and strip text."
        },
        "ncol": {
          "type": "integer",
          "minimum": 1,
          "description": "WRAP ONLY: number of panel columns (an integer of at least 1). Omit for an automatic near-square layout (ceil(sqrt(panels)))."
        },
        "scales": {
          "$ref": "#/$defs/FacetScales"
        },
        "strip": {
          "$ref": "#/$defs/FacetStripSpec"
        }
      },
      "additionalProperties": false,
      "description": "Facet the plot into small-multiple panels. Wrap form: set `wrap` (+ optional ncol). Grid form: set `rows` and/or `cols`. Panels partition the data BEFORE stats and positions run (each panel computes its own counts, bins, stacks). By default panel values sort ascending and strips sit on top; set field `levels`/`labels` and `strip.position`/`strip.show` for authored order, display text, and strip placement. Null values form their own panel when observed (or when listed in levels)."
    },
    "CoordTransformAxisSpec": {
      "type": "object",
      "required": [
        "transform"
      ],
      "properties": {
        "transform": {
          "anyOf": [
            {
              "type": "string",
              "const": "identity"
            },
            {
              "type": "string",
              "const": "log10"
            },
            {
              "type": "string",
              "const": "sqrt"
            }
          ],
          "description": "Post-stat coordinate transform for this axis: identity, base-10 logarithm, or square root."
        },
        "limits": {
          "type": "array",
          "items": {
            "type": "number"
          },
          "minItems": 2,
          "maxItems": 2,
          "description": "Optional coordinate viewport [min, max] in semantic/source units. Exactly two numbers. Unlike scale limits, coordinate limits do not remove rows or recompute statistics."
        },
        "reverse": {
          "type": "boolean",
          "description": "Reverse this coordinate axis after its transform without changing stat inputs or the trained semantic scale domain."
        },
        "expand": {
          "type": "boolean",
          "description": "Whether explicit coordinate limits receive the default 5% transformed-space display expansion (default true). Set false for exact viewport limits."
        }
      },
      "additionalProperties": false,
      "description": "One continuous coordinate axis projected after statistics and scale training. Non-identity transforms require a continuous, non-temporal position scale."
    },
    "CoordCartesianSpec": {
      "type": "object",
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "anyOf": [
            {
              "type": "string",
              "const": "cartesian"
            },
            {
              "type": "string",
              "const": "flip"
            }
          ],
          "description": "Coordinate system: \"cartesian\" (default) or \"flip\" (swap the axes: x renders vertically, y horizontally — THE mechanism for horizontal bar charts; positions, stacking, dodging, and hit-testing all follow)."
        }
      },
      "additionalProperties": false,
      "description": "The plot's Cartesian coordinate system. {\"type\": \"flip\"} turns any vertical composition into its horizontal counterpart."
    },
    "CoordTransformSpec": {
      "type": "object",
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "type": "string",
          "const": "transform",
          "description": "Project positions after stats/positions and scale training."
        },
        "x": {
          "$ref": "#/$defs/CoordTransformAxisSpec"
        },
        "y": {
          "$ref": "#/$defs/CoordTransformAxisSpec"
        },
        "clip": {
          "type": "boolean",
          "description": "Clip marks to the panel rectangle (default true). Set false only when intentional overflow should remain visible."
        }
      },
      "additionalProperties": false,
      "description": "A post-stat Cartesian coordinate transform with independent x/y projectors. It is intentionally distinct from pre-stat scale transforms."
    },
    "CoordFixedSpec": {
      "type": "object",
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "type": "string",
          "const": "fixed",
          "description": "Cartesian coordinates with a fixed physical data-unit ratio."
        },
        "ratio": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Physical y-unit length divided by physical x-unit length (default 1, equal units)."
        }
      },
      "additionalProperties": false,
      "description": "A fixed-aspect Cartesian coordinate system. Layout fits the largest centered data rectangle after chart chrome is allocated."
    },
    "CoordSfSpec": {
      "type": "object",
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "type": "string",
          "const": "sf",
          "description": "Simple-features coordinates for already-projected map data. Fixed-aspect layout; no CRS transform in v1."
        },
        "ratio": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Physical y-unit length divided by physical x-unit length (default 1, equal projected units)."
        }
      },
      "additionalProperties": false,
      "description": "Fixed-aspect coordinates for portable geom_sf maps. Data must already be projected; CRS reproject / graticules are deferred."
    },
    "CoordSpec": {
      "anyOf": [
        {
          "$ref": "#/$defs/CoordCartesianSpec"
        },
        {
          "$ref": "#/$defs/CoordTransformSpec"
        },
        {
          "$ref": "#/$defs/CoordFixedSpec"
        },
        {
          "$ref": "#/$defs/CoordSfSpec"
        }
      ],
      "description": "The plot coordinate system: ordinary Cartesian, flipped Cartesian, post-stat transformed, fixed-aspect, or simple-features fixed-aspect."
    },
    "PlotSpec": {
      "type": "object",
      "required": [
        "layers"
      ],
      "properties": {
        "$schema": {
          "type": "string",
          "description": "URL of the ggsvelte spec JSON Schema version this spec targets."
        },
        "edition": {
          "type": "integer",
          "minimum": 1,
          "description": "Defaults edition this spec was authored against (currently 2). normalize() stamps the current edition when absent, so a spec keeps ITS edition's default look (theme roles, categorical palette) even after ggsvelte's defaults improve in a later edition. Explicit theme/scale settings always win over edition defaults."
        },
        "data": {
          "$ref": "#/$defs/DataRef",
          "description": "Default data for all layers."
        },
        "datasets": {
          "type": "object",
          "additionalProperties": {
            "$ref": "#/$defs/InlineData"
          },
          "description": "Named inline datasets referenced by {\"name\": ...} data refs."
        },
        "aes": {
          "$ref": "#/$defs/Aes",
          "description": "Plot-level aesthetic mapping, inherited by every layer."
        },
        "layers": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/LayerSpec"
          },
          "minItems": 1,
          "description": "The plot's layers, drawn in array order (first = bottom). At least one layer."
        },
        "facet": {
          "$ref": "#/$defs/FacetSpec"
        },
        "coord": {
          "$ref": "#/$defs/CoordSpec"
        },
        "scales": {
          "$ref": "#/$defs/Scales"
        },
        "guides": {
          "$ref": "#/$defs/GuidesSpec"
        },
        "legend": {
          "$ref": "#/$defs/LegendSpec"
        },
        "labs": {
          "$ref": "#/$defs/Labs"
        },
        "theme": {
          "anyOf": [
            {
              "$ref": "#/$defs/ThemeName"
            },
            {
              "$ref": "#/$defs/ThemeSpec"
            }
          ],
          "description": "A registered theme name, or a theme object (named base + role overrides). Omit for the default theme."
        },
        "width": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Preferred plot width in px (greater than 0). The host may override."
        },
        "height": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Preferred plot height in px (greater than 0). The host may override."
        },
        "a11y": {
          "anyOf": [
            {
              "type": "string",
              "const": "auto"
            },
            {
              "type": "string",
              "const": "force-svg"
            }
          ],
          "description": "Accessibility mode: \"auto\" (default — layers may render to canvas per their `render` hint, paired with an off-screen description block) or \"force-svg\" (every layer renders as SVG DOM marks — use for assistive-technology-critical charts; canvas layers do not expose per-mark accessibility)."
        }
      },
      "additionalProperties": false,
      "description": "A complete ggsvelte plot specification: data + aesthetic mapping + one or more layers, in layered grammar. Strictly JSON (PortableSpec)."
    }
  },
  "$ref": "#/$defs/PlotSpec"
}
