Skip to main content
Glama

pixel_validate

Idempotent

Validate pixel art recipes before inspection or export to catch mistakes; returns revision ID, dimensions, frame timing, animations and clipping data without images or files.

Instructions

Check a pixel art recipe for mistakes before inspecting or exporting it. Returns its revision id, size, frame timing, animations and clipping, without images or files.

Input Schema

NameRequiredDescriptionDefault
fpsNoAlso check timing against a video frame rate (24, 25, "29.97", 30, 60 or a fraction): frameGrid lists durations off the grid.
projectNoA version-1 Pixelbolt recipe: {"version": 1, "name", "width", "height", "palette", "symbols"?, "frames": [{"name", "duration"?, "from"?, "ops"?, "layers"?}], "animations"?}; see pixel_help.
revisionNoRevision id from an earlier response, sent instead of project.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed3 schema fields changedv0.9.2
    • changedInput schema / properties / fps / description
      Previous value: -"Also check timing against a video frame rate (24, 25, 29.97, 30, 60 or a fraction): frameGrid lists frame durations that are not whole video frames, positions a sequence would lengthen, shorten or never show, and whether each loop closes on the grid."New value: +"Also check timing against a video frame rate (24, 25, \"29.97\", 30, 60 or a fraction): frameGrid lists durations off the grid."
    • changedInput schema / properties / project / description
      Previous value: -"A version-1 Pixelbolt recipe: {\"version\": 1, \"name\", \"width\", \"height\", \"palette\", \"symbols\"?, \"frames\": [{\"name\", \"duration\"?, \"from\"?, \"ops\"?, \"layers\"?}], \"animations\"?}. pixel_help explains it; its topic schema is the full JSON Schema. Mistakes come back with their exact path."New value: +"A version-1 Pixelbolt recipe: {\"version\": 1, \"name\", \"width\", \"height\", \"palette\", \"symbols\"?, \"frames\": [{\"name\", \"duration\"?, \"from\"?, \"ops\"?, \"layers\"?}], \"animations\"?}; see pixel_help."
    • changedInput schema / properties / revision / description
      Previous value: -"Revision id from an earlier Pixelbolt response. Send it instead of project to reuse that recipe, including after restarting with the same MCP --out directory."New value: +"Revision id from an earlier response, sent instead of project."
  2. Changed6 schema fields changedv0.9.1
    • removedInput schema / $defs
      Removed value: -{
      -  "frame": {
      -    "additionalProperties": false,
      -    "properties": {
      -      "anchor": {
      -        "description": "[x, y] in unscaled canvas pixels; the top-left corner of that pixel.",
      -        "items": {
      -          "maximum": 4096,
      -          "minimum": -4096,
      -          "type": "integer"
      -        },
      -        "maxItems": 2,
      -        "minItems": 2,
      -        "type": "array"
      -      },
      -      "duration": {
      -        "description": "Frame duration in milliseconds; default 100.",
      -        "maximum": 60000,
      -        "minimum": 1,
      -        "type": "integer"
      -      },
      -      "flipX": {
      -        "type": "boolean"
      -      },
      -      "flipY": {
      -        "type": "boolean"
      -      },
      -      "from": {
      -        "description": "Portable name: do not use Windows device names (CON, PRN, AUX, NUL, COM1–9, LPT1–9). Frame/animation names must be unique ignoring case.",
      -        "pattern": "^[a-zA-Z][a-zA-Z0-9_-]{0,63}$",
      -        "type": "string"
      -      },
      -      "layers": {
      -        "items": {
      -          "$ref": "#/$defs/layer"
      -        },
      -        "maxItems": 64,
      -        "type": "array"
      -      },
      -      "name": {
      -        "description": "Portable name: do not use Windows device names (CON, PRN, AUX, NUL, COM1–9, LPT1–9). Frame/animation names must be unique ignoring case.",
      -        "pattern": "^[a-zA-Z][a-zA-Z0-9_-]{0,63}$",
      -        "type": "string"
      -      },
      -      "ops": {
      -        "items": {
      -          "$ref": "#/$defs/op"
      -        },
      -        "maxItems": 2048,
      -        "type": "array"
      -      },
      -      "palette": {
      -        "additionalProperties": {
      -          "description": "Palette name, transparent, or #RGB/#RGBA/#RRGGBB/#RRGGBBAA.",
      -          "type": "string"
      -        },
      -        "description": "Recolor project palette keys for this frame only (palette cycling). Keys must exist in the project palette.",
      -        "maxProperties": 256,
      -        "type": "object"
      -      },
      -      "pixels": {
      -        "description": "Final canvas-coordinate RGBA replacements after ops and layers. Coordinates must be inside this canvas. Later entries win; transparent erases.",
      -        "items": {
      -          "$ref": "#/$defs/pixel"
      -        },
      -        "maxItems": 65536,
      -        "type": "array"
      -      },
      -      "points": {
      -        "additionalProperties": {
      -          "description": "[x, y] in unscaled canvas pixels; the top-left corner of that pixel.",
      -          "items": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          },
      -          "maxItems": 2,
      -          "minItems": 2,
      -          "type": "array"
      -        },
      -        "description": "Named frame positions (hands, hit points, glyph advance), exported in the atlas in exported pixels.",
      -        "maxProperties": 64,
      -        "propertyNames": {
      -          "description": "Portable name: do not use Windows device names (CON, PRN, AUX, NUL, COM1–9, LPT1–9). Frame/animation names must be unique ignoring case.",
      -          "pattern": "^[a-zA-Z][a-zA-Z0-9_-]{0,63}$",
      -          "type": "string"
      -        },
      -        "type": "object"
      -      },
      -      "translate": {
      -        "items": {
      -          "maximum": 4096,
      -          "minimum": -4096,
      -          "type": "integer"
      -        },
      -        "maxItems": 2,
      -        "minItems": 2,
      -        "type": "array"
      -      },
      -      "wrap": {
      -        "description": "Translation wraps around the canvas instead of clipping (scrolling tiles).",
      -        "type": "boolean"
      -      }
      -    },
      -    "required": [
      -      "name"
      -    ],
      -    "type": "object"
      -  },
      -  "layer": {
      -    "additionalProperties": false,
      -    "properties": {
      -      "name": {
      -        "description": "Portable name: do not use Windows device names (CON, PRN, AUX, NUL, COM1–9, LPT1–9). Frame/animation names must be unique ignoring case.",
      -        "pattern": "^[a-zA-Z][a-zA-Z0-9_-]{0,63}$",
      -        "type": "string"
      -      },
      -      "opacity": {
      -        "maximum": 1,
      -        "minimum": 0,
      -        "type": "number"
      -      },
      -      "ops": {
      -        "items": {
      -          "$ref": "#/$defs/op"
      -        },
      -        "maxItems": 2048,
      -        "type": "array"
      -      },
      -      "palette": {
      -        "additionalProperties": {
      -          "description": "Palette name, transparent, or #RGB/#RGBA/#RRGGBB/#RRGGBBAA.",
      -          "type": "string"
      -        },
      -        "description": "Recolor project palette keys for this layer's drawing only, on top of the frame palette: a flash or cycle on one layer leaves other drawing that shares the key alone. Keys must exist in the project palette; values are colours or project palette names.",
      -        "maxProperties": 256,
      -        "type": "object"
      -      },
      -      "visible": {
      -        "type": "boolean"
      -      },
      -      "x": {
      -        "maximum": 4096,
      -        "minimum": -4096,
      -        "type": "integer"
      -      },
      -      "y": {
      -        "maximum": 4096,
      -        "minimum": -4096,
      -        "type": "integer"
      -      }
      -    },
      -    "required": [],
      -    "type": "object"
      -  },
      -  "op": {
      -    "oneOf": [
      -      {
      -        "additionalProperties": false,
      -        "properties": {
      -          "color": {
      -            "description": "Palette name, transparent, or #RGB/#RGBA/#RRGGBB/#RRGGBBAA.",
      -            "type": "string"
      -          },
      -          "op": {
      -            "const": "pixel"
      -          },
      -          "x": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          },
      -          "y": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          }
      -        },
      -        "required": [
      -          "op",
      -          "color"
      -        ],
      -        "type": "object"
      -      },
      -      {
      -        "additionalProperties": false,
      -        "properties": {
      -          "color": {
      -            "description": "Palette name, transparent, or #RGB/#RGBA/#RRGGBB/#RRGGBBAA.",
      -            "type": "string"
      -          },
      -          "filled": {
      -            "type": "boolean"
      -          },
      -          "h": {
      -            "maximum": 512,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "op": {
      -            "const": "rect"
      -          },
      -          "w": {
      -            "maximum": 512,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "x": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          },
      -          "y": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          }
      -        },
      -        "required": [
      -          "op",
      -          "w",
      -          "h",
      -          "color"
      -        ],
      -        "type": "object"
      -      },
      -      {
      -        "additionalProperties": false,
      -        "properties": {
      -          "color": {
      -            "description": "Palette name, transparent, or #RGB/#RGBA/#RRGGBB/#RRGGBBAA.",
      -            "type": "string"
      -          },
      -          "filled": {
      -            "type": "boolean"
      -          },
      -          "h": {
      -            "maximum": 512,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "op": {
      -            "const": "ellipse"
      -          },
      -          "w": {
      -            "maximum": 512,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "x": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          },
      -          "y": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          }
      -        },
      -        "required": [
      -          "op",
      -          "w",
      -          "h",
      -          "color"
      -        ],
      -        "type": "object"
      -      },
      -      {
      -        "additionalProperties": false,
      -        "properties": {
      -          "color": {
      -            "description": "Palette name, transparent, or #RGB/#RGBA/#RRGGBB/#RRGGBBAA.",
      -            "type": "string"
      -          },
      -          "op": {
      -            "const": "line"
      -          },
      -          "x": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          },
      -          "x2": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          },
      -          "y": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          },
      -          "y2": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          }
      -        },
      -        "required": [
      -          "op",
      -          "x2",
      -          "y2",
      -          "color"
      -        ],
      -        "type": "object"
      -      },
      -      {
      -        "additionalProperties": false,
      -        "properties": {
      -          "h": {
      -            "maximum": 512,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "op": {
      -            "const": "clear"
      -          },
      -          "w": {
      -            "maximum": 512,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "x": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          },
      -          "y": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          }
      -        },
      -        "required": [
      -          "op",
      -          "w",
      -          "h"
      -        ],
      -        "type": "object"
      -      },
      -      {
      -        "additionalProperties": false,
      -        "properties": {
      -          "color": {
      -            "description": "Palette name, transparent, or #RGB/#RGBA/#RRGGBB/#RRGGBBAA.",
      -            "type": "string"
      -          },
      -          "op": {
      -            "const": "fill"
      -          },
      -          "x": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          },
      -          "y": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          }
      -        },
      -        "required": [
      -          "op",
      -          "color"
      -        ],
      -        "type": "object"
      -      },
      -      {
      -        "additionalProperties": false,
      -        "properties": {
      -          "from": {
      -            "description": "Palette name, transparent, or #RGB/#RGBA/#RRGGBB/#RRGGBBAA.",
      -            "type": "string"
      -          },
      -          "op": {
      -            "const": "replace"
      -          },
      -          "to": {
      -            "description": "Palette name, transparent, or #RGB/#RGBA/#RRGGBB/#RRGGBBAA.",
      -            "type": "string"
      -          }
      -        },
      -        "required": [
      -          "op",
      -          "from",
      -          "to"
      -        ],
      -        "type": "object"
      -      },
      -      {
      -        "additionalProperties": false,
      -        "properties": {
      -          "flipX": {
      -            "type": "boolean"
      -          },
      -          "flipY": {
      -            "type": "boolean"
      -          },
      -          "op": {
      -            "const": "grid"
      -          },
      -          "remap": {
      -            "additionalProperties": {
      -              "description": "Palette name, transparent, or #RGB/#RGBA/#RRGGBB/#RRGGBBAA.",
      -              "type": "string"
      -            },
      -            "description": "Recolor grid characters for this operation only: character → palette name or colour.",
      -            "propertyNames": {
      -              "maxLength": 1,
      -              "minLength": 1
      -            },
      -            "type": "object"
      -          },
      -          "rotate": {
      -            "enum": [
      -              0,
      -              90,
      -              180,
      -              270
      -            ]
      -          },
      -          "rows": {
      -            "$ref": "#/$defs/rows"
      -          },
      -          "scale": {
      -            "maximum": 16,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "x": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          },
      -          "y": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          }
      -        },
      -        "required": [
      -          "op",
      -          "rows"
      -        ],
      -        "type": "object"
      -      },
      -      {
      -        "additionalProperties": false,
      -        "properties": {
      -          "flipX": {
      -            "type": "boolean"
      -          },
      -          "flipY": {
      -            "type": "boolean"
      -          },
      -          "op": {
      -            "const": "stamp"
      -          },
      -          "remap": {
      -            "additionalProperties": {
      -              "description": "Palette name, transparent, or #RGB/#RGBA/#RRGGBB/#RRGGBBAA.",
      -              "type": "string"
      -            },
      -            "description": "Recolor grid characters for this operation only: character → palette name or colour.",
      -            "propertyNames": {
      -              "maxLength": 1,
      -              "minLength": 1
      -            },
      -            "type": "object"
      -          },
      -          "rotate": {
      -            "enum": [
      -              0,
      -              90,
      -              180,
      -              270
      -            ]
      -          },
      -          "scale": {
      -            "maximum": 16,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "symbol": {
      -            "description": "Portable name: do not use Windows device names (CON, PRN, AUX, NUL, COM1–9, LPT1–9). Frame/animation names must be unique ignoring case.",
      -            "pattern": "^[a-zA-Z][a-zA-Z0-9_-]{0,63}$",
      -            "type": "string"
      -          },
      -          "x": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          },
      -          "y": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          }
      -        },
      -        "required": [
      -          "op",
      -          "symbol"
      -        ],
      -        "type": "object"
      -      },
      -      {
      -        "additionalProperties": false,
      -        "description": "Draw text in the built-in pixel font. y is the top of the capitals; a line is 8 rows: capitals 7 tall, lowercase 5, descenders 1 below, and the accent of a capital reaches 2 rows above y. Glyphs are 1 to 5 pixels wide (© ® — Œ œ are 7), digits always 5, a space 3. One line of n average characters is about 6n pixels wide.",
      -        "properties": {
      -          "align": {
      -            "description": "What x is: the left edge of the text (default), its centre or its right edge. Lines align the same way.",
      -            "enum": [
      -              "left",
      -              "center",
      -              "right"
      -            ]
      -          },
      -          "color": {
      -            "description": "Palette name, transparent, or #RGB/#RGBA/#RRGGBB/#RRGGBBAA.",
      -            "type": "string"
      -          },
      -          "flipX": {
      -            "type": "boolean"
      -          },
      -          "flipY": {
      -            "type": "boolean"
      -          },
      -          "lineHeight": {
      -            "description": "Pixels from the top of one line to the top of the next; default 10.",
      -            "maximum": 64,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "op": {
      -            "const": "text"
      -          },
      -          "rotate": {
      -            "enum": [
      -              0,
      -              90,
      -              180,
      -              270
      -            ]
      -          },
      -          "scale": {
      -            "maximum": 16,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "spacing": {
      -            "description": "Pixels between glyphs; default 1.",
      -            "maximum": 16,
      -            "minimum": 0,
      -            "type": "integer"
      -          },
      -          "text": {
      -            "description": "Printable ASCII, western European accented letters and common symbols; \\n starts a new line (at most 64).",
      -            "maxLength": 512,
      -            "minLength": 1,
      -            "type": "string"
      -          },
      -          "x": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          },
      -          "y": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          }
      -        },
      -        "required": [
      -          "op",
      -          "text",
      -          "color"
      -        ],
      -        "type": "object"
      -      },
      -      {
      -        "additionalProperties": false,
      -        "description": "Copy a rectangle of a symbol (palette characters) or an earlier frame (exact RGBA).",
      -        "oneOf": [
      -          {
      -            "required": [
      -              "from"
      -            ]
      -          },
      -          {
      -            "required": [
      -              "symbol"
      -            ]
      -          }
      -        ],
      -        "properties": {
      -          "flipX": {
      -            "type": "boolean"
      -          },
      -          "flipY": {
      -            "type": "boolean"
      -          },
      -          "from": {
      -            "description": "Portable name: do not use Windows device names (CON, PRN, AUX, NUL, COM1–9, LPT1–9). Frame/animation names must be unique ignoring case.",
      -            "pattern": "^[a-zA-Z][a-zA-Z0-9_-]{0,63}$",
      -            "type": "string"
      -          },
      -          "h": {
      -            "maximum": 256,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "op": {
      -            "const": "copy"
      -          },
      -          "remap": {
      -            "additionalProperties": {
      -              "description": "Palette name, transparent, or #RGB/#RGBA/#RRGGBB/#RRGGBBAA.",
      -              "type": "string"
      -            },
      -            "description": "Symbol copies: recolor grid characters (one character each) → palette name or colour. Frame copies: swap exact colours, named by project palette key or hex (#RGB to #RRGGBBAA), for a palette name or colour.",
      -            "maxProperties": 256,
      -            "propertyNames": {
      -              "maxLength": 64,
      -              "minLength": 1
      -            },
      -            "type": "object"
      -          },
      -          "rotate": {
      -            "enum": [
      -              0,
      -              90,
      -              180,
      -              270
      -            ]
      -          },
      -          "scale": {
      -            "maximum": 16,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "sx": {
      -            "maximum": 255,
      -            "minimum": 0,
      -            "type": "integer"
      -          },
      -          "sy": {
      -            "maximum": 255,
      -            "minimum": 0,
      -            "type": "integer"
      -          },
      -          "symbol": {
      -            "description": "Portable name: do not use Windows device names (CON, PRN, AUX, NUL, COM1–9, LPT1–9). Frame/animation names must be unique ignoring case.",
      -            "pattern": "^[a-zA-Z][a-zA-Z0-9_-]{0,63}$",
      -            "type": "string"
      -          },
      -          "w": {
      -            "maximum": 256,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "x": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          },
      -          "y": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          }
      -        },
      -        "required": [
      -          "op"
      -        ],
      -        "type": "object"
      -      },
      -      {
      -        "additionalProperties": false,
      -        "description": "Draw one autotile tile from a template symbol two tiles wide and three tall: the four quarters the mask selects (see the autotile template format). The autotile compiler emits one per frame, so editing the template redraws every tile.",
      -        "properties": {
      -          "mask": {
      -            "description": "Neighbour mask. Blob: N=1, NE=2, E=4, SE=8, S=16, SW=32, W=64, NW=128, reduced so a diagonal counts only with both of its sides. Cardinal: N=1, E=2, S=4, W=8.",
      -            "maximum": 255,
      -            "minimum": 0,
      -            "type": "integer"
      -          },
      -          "mode": {
      -            "description": "blob (default) or cardinal.",
      -            "enum": [
      -              "blob",
      -              "cardinal"
      -            ]
      -          },
      -          "op": {
      -            "const": "autotile"
      -          },
      -          "remap": {
      -            "additionalProperties": {
      -              "description": "Palette name, transparent, or #RGB/#RGBA/#RRGGBB/#RRGGBBAA.",
      -              "type": "string"
      -            },
      -            "description": "Recolor grid characters for this operation only: character → palette name or colour.",
      -            "propertyNames": {
      -              "maxLength": 1,
      -              "minLength": 1
      -            },
      -            "type": "object"
      -          },
      -          "symbol": {
      -            "description": "Portable name: do not use Windows device names (CON, PRN, AUX, NUL, COM1–9, LPT1–9). Frame/animation names must be unique ignoring case.",
      -            "pattern": "^[a-zA-Z][a-zA-Z0-9_-]{0,63}$",
      -            "type": "string"
      -          },
      -          "x": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          },
      -          "y": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          }
      -        },
      -        "required": [
      -          "op",
      -          "symbol",
      -          "mask"
      -        ],
      -        "type": "object"
      -      },
      -      {
      -        "additionalProperties": false,
      -        "description": "Outline every visible pixel in this buffer (frame or layer): outside rings, inside edge rings or both, in chosen directions.",
      -        "properties": {
      -          "color": {
      -            "description": "Palette name, transparent, or #RGB/#RGBA/#RRGGBB/#RRGGBBAA.",
      -            "type": "string"
      -          },
      -          "diagonal": {
      -            "type": "boolean"
      -          },
      -          "directions": {
      -            "description": "3×3 grid centred on a visible pixel, with a dot in the centre: x marks the sides that get the line, e.g. [\"...\", \"...\", \"..x\"] for a drop shadow or [\".x.\", \"...\", \"...\"] for a top rim. Replaces diagonal.",
      -            "items": {
      -              "pattern": "^[x.]{3}$",
      -              "type": "string"
      -            },
      -            "maxItems": 3,
      -            "minItems": 3,
      -            "type": "array"
      -          },
      -          "op": {
      -            "const": "outline"
      -          },
      -          "position": {
      -            "description": "outside (default) surrounds the visible pixels; inside recolors their edge pixels; middle splits the width, the odd pixel outside.",
      -            "enum": [
      -              "outside",
      -              "inside",
      -              "middle"
      -            ]
      -          },
      -          "width": {
      -            "description": "Rings of pixels; default 1.",
      -            "maximum": 8,
      -            "minimum": 1,
      -            "type": "integer"
      -          }
      -        },
      -        "required": [
      -          "op",
      -          "color"
      -        ],
      -        "type": "object"
      -      },
      -      {
      -        "additionalProperties": false,
      -        "anyOf": [
      -          {
      -            "required": [
      -              "color"
      -            ]
      -          },
      -          {
      -            "required": [
      -              "erase"
      -            ]
      -          }
      -        ],
      -        "description": "Ordered dither between the current pixels and color: draws (or erases) where a canvas-anchored threshold pattern is below the density (default 0.5). x/y default to 0 and w/h reach the canvas edge.",
      -        "properties": {
      -          "color": {
      -            "description": "Palette name, transparent, or #RGB/#RGBA/#RRGGBB/#RRGGBBAA.",
      -            "type": "string"
      -          },
      -          "density": {
      -            "description": "Share of pixels changed, 0–1, or [from, to] ramping along direction.",
      -            "oneOf": [
      -              {
      -                "maximum": 1,
      -                "minimum": 0,
      -                "type": "number"
      -              },
      -              {
      -                "items": {
      -                  "maximum": 1,
      -                  "minimum": 0,
      -                  "type": "number"
      -                },
      -                "maxItems": 2,
      -                "minItems": 2,
      -                "type": "array"
      -              }
      -            ]
      -          },
      -          "direction": {
      -            "description": "Ramp direction for a [from, to] density; radial runs from the centre to the edge.",
      -            "enum": [
      -              "down",
      -              "up",
      -              "right",
      -              "left",
      -              "radial"
      -            ]
      -          },
      -          "erase": {
      -            "description": "Clear the pattern pixels instead of drawing a color.",
      -            "type": "boolean"
      -          },
      -          "h": {
      -            "maximum": 512,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "offset": {
      -            "description": "Shift the pattern, for example to crawl it between frames.",
      -            "items": {
      -              "maximum": 4096,
      -              "minimum": -4096,
      -              "type": "integer"
      -            },
      -            "maxItems": 2,
      -            "minItems": 2,
      -            "type": "array"
      -          },
      -          "op": {
      -            "const": "dither"
      -          },
      -          "over": {
      -            "description": "Only change pixels whose exact current color is listed (transparent included).",
      -            "oneOf": [
      -              {
      -                "description": "Palette name, transparent, or #RGB/#RGBA/#RRGGBB/#RRGGBBAA.",
      -                "type": "string"
      -              },
      -              {
      -                "items": {
      -                  "description": "Palette name, transparent, or #RGB/#RGBA/#RRGGBB/#RRGGBBAA.",
      -                  "type": "string"
      -                },
      -                "maxItems": 64,
      -                "minItems": 1,
      -                "type": "array"
      -              }
      -            ]
      -          },
      -          "pattern": {
      -            "description": "bayer4 by default. noise is seeded white noise with no repeating grid; value is seeded smooth noise that forms clumps about scale pixels across. Patterns follow canvas coordinates, so neighbouring areas line up.",
      -            "oneOf": [
      -              {
      -                "enum": [
      -                  "bayer2",
      -                  "bayer4",
      -                  "bayer8",
      -                  "noise",
      -                  "value"
      -                ]
      -              },
      -              {
      -                "description": "Rows of ranks from 0 to cells − 1; low ranks turn on first, and a highest rank n gives n + 1 levels, so [[0, 1], [1, 0]] is a checkerboard at 0.5.",
      -                "items": {
      -                  "items": {
      -                    "maximum": 255,
      -                    "minimum": 0,
      -                    "type": "integer"
      -                  },
      -                  "maxItems": 16,
      -                  "minItems": 1,
      -                  "type": "array"
      -                },
      -                "maxItems": 16,
      -                "minItems": 1,
      -                "type": "array"
      -              }
      -            ]
      -          },
      -          "scale": {
      -            "description": "Clump size of the value pattern in pixels; default 4.",
      -            "maximum": 64,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "seed": {
      -            "description": "Orders the noise or value pattern (default 0): the same seed keeps every pixel's threshold, so a rising density grows in a fixed order; another seed reshuffles it.",
      -            "maximum": 2147483647,
      -            "minimum": 0,
      -            "type": "integer"
      -          },
      -          "w": {
      -            "maximum": 512,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "x": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          },
      -          "y": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          }
      -        },
      -        "required": [
      -          "op"
      -        ],
      -        "type": "object"
      -      },
      -      {
      -        "additionalProperties": false,
      -        "description": "Move every pixel of the region along its colour's ramp (see ramps), so shadows and light keep the palette on any surface. Colours on no ramp stay. density (default 1) and pattern give a dithered edge. x/y default to 0 and w/h reach the canvas edge.",
      -        "properties": {
      -          "density": {
      -            "description": "Share of pixels changed, 0–1, or [from, to] ramping along direction.",
      -            "oneOf": [
      -              {
      -                "maximum": 1,
      -                "minimum": 0,
      -                "type": "number"
      -              },
      -              {
      -                "items": {
      -                  "maximum": 1,
      -                  "minimum": 0,
      -                  "type": "number"
      -                },
      -                "maxItems": 2,
      -                "minItems": 2,
      -                "type": "array"
      -              }
      -            ]
      -          },
      -          "direction": {
      -            "description": "Ramp direction for a [from, to] density; radial runs from the centre to the edge.",
      -            "enum": [
      -              "down",
      -              "up",
      -              "right",
      -              "left",
      -              "radial"
      -            ]
      -          },
      -          "h": {
      -            "maximum": 512,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "offset": {
      -            "description": "Shift the pattern, for example to crawl it between frames.",
      -            "items": {
      -              "maximum": 4096,
      -              "minimum": -4096,
      -              "type": "integer"
      -            },
      -            "maxItems": 2,
      -            "minItems": 2,
      -            "type": "array"
      -          },
      -          "op": {
      -            "const": "shade"
      -          },
      -          "over": {
      -            "description": "Only change pixels whose exact current color is listed (transparent included).",
      -            "oneOf": [
      -              {
      -                "description": "Palette name, transparent, or #RGB/#RGBA/#RRGGBB/#RRGGBBAA.",
      -                "type": "string"
      -              },
      -              {
      -                "items": {
      -                  "description": "Palette name, transparent, or #RGB/#RGBA/#RRGGBB/#RRGGBBAA.",
      -                  "type": "string"
      -                },
      -                "maxItems": 64,
      -                "minItems": 1,
      -                "type": "array"
      -              }
      -            ]
      -          },
      -          "pattern": {
      -            "description": "bayer4 by default. noise is seeded white noise with no repeating grid; value is seeded smooth noise that forms clumps about scale pixels across. Patterns follow canvas coordinates, so neighbouring areas line up.",
      -            "oneOf": [
      -              {
      -                "enum": [
      -                  "bayer2",
      -                  "bayer4",
      -                  "bayer8",
      -                  "noise",
      -                  "value"
      -                ]
      -              },
      -              {
      -                "description": "Rows of ranks from 0 to cells − 1; low ranks turn on first, and a highest rank n gives n + 1 levels, so [[0, 1], [1, 0]] is a checkerboard at 0.5.",
      -                "items": {
      -                  "items": {
      -                    "maximum": 255,
      -                    "minimum": 0,
      -                    "type": "integer"
      -                  },
      -                  "maxItems": 16,
      -                  "minItems": 1,
      -                  "type": "array"
      -                },
      -                "maxItems": 16,
      -                "minItems": 1,
      -                "type": "array"
      -              }
      -            ]
      -          },
      -          "scale": {
      -            "description": "Clump size of the value pattern in pixels; default 4.",
      -            "maximum": 64,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "seed": {
      -            "description": "Orders the noise or value pattern (default 0): the same seed keeps every pixel's threshold, so a rising density grows in a fixed order; another seed reshuffles it.",
      -            "maximum": 2147483647,
      -            "minimum": 0,
      -            "type": "integer"
      -          },
      -          "shape": {
      -            "description": "rect (default) or the ellipse inside the region.",
      -            "enum": [
      -              "rect",
      -              "ellipse"
      -            ]
      -          },
      -          "steps": {
      -            "description": "Steps along each colour's ramp: negative darkens (default -1), positive lightens. Clamped at the ramp's ends; not 0.",
      -            "maximum": 8,
      -            "minimum": -8,
      -            "type": "integer"
      -          },
      -          "w": {
      -            "maximum": 512,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "x": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          },
      -          "y": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          }
      -        },
      -        "required": [
      -          "op"
      -        ],
      -        "type": "object"
      -      },
      -      {
      -        "additionalProperties": false,
      -        "description": "Draw a character map from this recipe's symbols and autotile templates, with variants, weights and neighbour rules, so later operations see the composed result (dither over its floor, rewrite rules at its corners).",
      -        "properties": {
      -          "classes": {
      -            "additionalProperties": {
      -              "maxLength": 64,
      -              "minLength": 1,
      -              "type": "string"
      -            },
      -            "description": "Characters that stand for several map characters in rule patterns, e.g. {\"#\": \"WV\"}; include the empty character to match empty cells too.",
      -            "propertyNames": {
      -              "maxLength": 1,
      -              "minLength": 1
      -            },
      -            "type": "object"
      -          },
      -          "empty": {
      -            "description": "A character, not a legend key, that stands for empty cells in rule patterns.",
      -            "maxLength": 1,
      -            "minLength": 1,
      -            "type": "string"
      -          },
      -          "legend": {
      -            "additionalProperties": {
      -              "oneOf": [
      -                {
      -                  "description": "A symbol drawn at the cell's top-left; with autotile, {mask} in its name becomes the neighbour mask.",
      -                  "type": "string"
      -                },
      -                {
      -                  "additionalProperties": false,
      -                  "properties": {
      -                    "autotile": {
      -                      "description": "Pick by neighbour mask: 47-value blob or 16-value cardinal.",
      -                      "enum": [
      -                        "blob",
      -                        "cardinal"
      -                      ]
      -                    },
      -                    "match": {
      -                      "description": "Characters counted as the same terrain for the mask; default: this character.",
      -                      "minLength": 1,
      -                      "type": "string"
      -                    },
      -                    "symbol": {
      -                      "description": "A symbol drawn at the cell's top-left; with autotile, {mask} in its name becomes the neighbour mask.",
      -                      "type": "string"
      -                    },
      -                    "symbols": {
      -                      "description": "Variants of symbol, picked by cell position (seeded when the tilemap has a seed).",
      -                      "items": {
      -                        "minLength": 1,
      -                        "type": "string"
      -                      },
      -                      "maxItems": 64,
      -                      "minItems": 1,
      -                      "type": "array"
      -                    },
      -                    "template": {
      -                      "description": "An autotile template symbol (two tiles wide, three tall) drawn with the cell's neighbour mask; needs autotile.",
      -                      "type": "string"
      -                    },
      -                    "templates": {
      -                      "description": "Variants of template, picked by cell position (seeded when the tilemap has a seed).",
      -                      "items": {
      -                        "minLength": 1,
      -                        "type": "string"
      -                      },
      -                      "maxItems": 64,
      -                      "minItems": 1,
      -                      "type": "array"
      -                    },
      -                    "weights": {
      -                      "description": "One whole-number weight per variant name; heavier names are picked more often.",
      -                      "items": {
      -                        "maximum": 1000,
      -                        "minimum": 1,
      -                        "type": "integer"
      -                      },
      -                      "maxItems": 64,
      -                      "minItems": 1,
      -                      "type": "array"
      -                    }
      -                  },
      -                  "required": [],
      -                  "type": "object"
      -                },
      -                {
      -                  "additionalProperties": false,
      -                  "properties": {
      -                    "rules": {
      -                      "description": "Every rule that matches draws, in order, until one with stop draws.",
      -                      "items": {
      -                        "additionalProperties": false,
      -                        "properties": {
      -                          "autotile": {
      -                            "description": "Pick by neighbour mask: 47-value blob or 16-value cardinal.",
      -                            "enum": [
      -                              "blob",
      -                              "cardinal"
      -                            ]
      -                          },
      -                          "chance": {
      -                            "description": "Seeded probability that a matching rule draws.",
      -                            "maximum": 1,
      -                            "minimum": 0,
      -                            "type": "number"
      -                          },
      -                          "match": {
      -                            "description": "Characters counted as the same terrain for the mask; default: this character.",
      -                            "minLength": 1,
      -                            "type": "string"
      -                          },
      -                          "offset": {
      -                            "description": "[columns, rows] to draw into another cell; it draws over that cell's own tiles.",
      -                            "items": {
      -                              "maximum": 8,
      -                              "minimum": -8,
      -                              "type": "integer"
      -                            },
      -                            "maxItems": 2,
      -                            "minItems": 2,
      -                            "type": "array"
      -                          },
      -                          "stop": {
      -                            "description": "When this rule draws, skip the rest of the cell's rules.",
      -                            "type": "boolean"
      -                          },
      -                          "symbol": {
      -                            "description": "A symbol drawn at the cell's top-left; with autotile, {mask} in its name becomes the neighbour mask.",
      -                            "type": "string"
      -                          },
      -                          "symbols": {
      -                            "description": "Variants of symbol, picked by cell position (seeded when the tilemap has a seed).",
      -                            "items": {
      -                              "minLength": 1,
      -                              "type": "string"
      -                            },
      -                            "maxItems": 64,
      -                            "minItems": 1,
      -                            "type": "array"
      -                          },
      -                          "template": {
      -                            "description": "An autotile template symbol (two tiles wide, three tall) drawn with the cell's neighbour mask; needs autotile.",
      -                            "type": "string"
      -                          },
      -                          "templates": {
      -                            "description": "Variants of template, picked by cell position (seeded when the tilemap has a seed).",
      -                            "items": {
      -                              "minLength": 1,
      -                              "type": "string"
      -                            },
      -                            "maxItems": 64,
      -                            "minItems": 1,
      -                            "type": "array"
      -                          },
      -                          "weights": {
      -                            "description": "One whole-number weight per variant name; heavier names are picked more often.",
      -                            "items": {
      -                              "maximum": 1000,
      -                              "minimum": 1,
      -                              "type": "integer"
      -                            },
      -                            "maxItems": 64,
      -                            "minItems": 1,
      -                            "type": "array"
      -                          },
      -                          "where": {
      -                            "description": "3×3 characters centred on the cell. A dot matches anything, the tilemap's empty character matches empty cells (and cells beyond the map), a class matches its members, any other character matches itself.",
      -                            "items": {
      -                              "maxLength": 3,
      -                              "minLength": 3,
      -                              "type": "string"
      -                            },
      -                            "maxItems": 3,
      -                            "minItems": 3,
      -                            "type": "array"
      -                          }
      -                        },
      -                        "required": [],
      -                        "type": "object"
      -                      },
      -                      "maxItems": 32,
      -                      "minItems": 1,
      -                      "type": "array"
      -                    }
      -                  },
      -                  "required": [
      -                    "rules"
      -                  ],
      -                  "type": "object"
      -                },
      -                {
      -                  "description": "Context cell: never drawn, but it counts for other entries' match and for rules.",
      -                  "type": "null"
      -                }
      -              ]
      -            },
      -            "description": "Map characters to what they draw. Dot and space are empty cells.",
      -            "propertyNames": {
      -              "maxLength": 1,
      -              "minLength": 1
      -            },
      -            "type": "object"
      -          },
      -          "op": {
      -            "const": "tilemap"
      -          },
      -          "outside": {
      -            "description": "Cells beyond the map: empty (default), or matching every mask and rule pattern.",
      -            "enum": [
      -              "empty",
      -              "match"
      -            ]
      -          },
      -          "rows": {
      -            "items": {
      -              "maxLength": 256,
      -              "minLength": 1,
      -              "type": "string"
      -            },
      -            "maxItems": 256,
      -            "minItems": 1,
      -            "type": "array"
      -          },
      -          "seed": {
      -            "description": "Reorders seeded variant picks and rule chances; default 0 keeps position-based picks.",
      -            "maximum": 2147483647,
      -            "minimum": 0,
      -            "type": "integer"
      -          },
      -          "tile": {
      -            "description": "Cell size [width, height] in pixels.",
      -            "items": {
      -              "maximum": 256,
      -              "minimum": 1,
      -              "type": "integer"
      -            },
      -            "maxItems": 2,
      -            "minItems": 2,
      -            "type": "array"
      -          },
      -          "x": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          },
      -          "y": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          }
      -        },
      -        "required": [
      -          "op",
      -          "tile",
      -          "rows",
      -          "legend"
      -        ],
      -        "type": "object"
      -      },
      -      {
      -        "additionalProperties": false,
      -        "description": "Markov-style rewrite rules on this buffer: each small match grid found on exact colors is replaced, in a seeded order, without overlapping rewrites. The region defaults to the whole canvas.",
      -        "properties": {
      -          "chance": {
      -            "description": "Seeded probability that each match is applied.",
      -            "maximum": 1,
      -            "minimum": 0,
      -            "type": "number"
      -          },
      -          "empty": {
      -            "description": "A non-palette character meaning a transparent pixel in match and erasure in replace.",
      -            "maxLength": 1,
      -            "minLength": 1,
      -            "type": "string"
      -          },
      -          "h": {
      -            "maximum": 512,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "limit": {
      -            "description": "Most replacements per rule per step.",
      -            "maximum": 65536,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "mirror": {
      -            "description": "Also match the rules mirrored horizontally.",
      -            "type": "boolean"
      -          },
      -          "op": {
      -            "const": "rewrite"
      -          },
      -          "rotate": {
      -            "description": "Also match the rules turned 90°, 180° and 270°.",
      -            "type": "boolean"
      -          },
      -          "rules": {
      -            "items": {
      -              "additionalProperties": false,
      -              "properties": {
      -                "match": {
      -                  "description": "Equal-width rows of palette keys; dot or space matches anything (match) or keeps the pixel (replace); the empty character stands for transparent.",
      -                  "items": {
      -                    "maxLength": 8,
      -                    "minLength": 1,
      -                    "type": "string"
      -                  },
      -                  "maxItems": 8,
      -                  "minItems": 1,
      -                  "type": "array"
      -                },
      -                "replace": {
      -                  "description": "Equal-width rows of palette keys; dot or space matches anything (match) or keeps the pixel (replace); the empty character stands for transparent.",
      -                  "items": {
      -                    "maxLength": 8,
      -                    "minLength": 1,
      -                    "type": "string"
      -                  },
      -                  "maxItems": 8,
      -                  "minItems": 1,
      -                  "type": "array"
      -                }
      -              },
      -              "required": [
      -                "match",
      -                "replace"
      -              ],
      -              "type": "object"
      -            },
      -            "maxItems": 16,
      -            "minItems": 1,
      -            "type": "array"
      -          },
      -          "seed": {
      -            "maximum": 2147483647,
      -            "minimum": 0,
      -            "type": "integer"
      -          },
      -          "steps": {
      -            "description": "Passes over every rule; stops early when a pass changes nothing.",
      -            "maximum": 64,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "w": {
      -            "maximum": 512,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "x": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          },
      -          "y": {
      -            "maximum": 4096,
      -            "minimum": -4096,
      -            "type": "integer"
      -          }
      -        },
      -        "required": [
      -          "op",
      -          "rules"
      -        ],
      -        "type": "object"
      -      }
      -    ]
      -  },
      -  "pixel": {
      -    "additionalProperties": false,
      -    "properties": {
      -      "color": {
      -        "description": "Palette name, transparent, or #RGB/#RGBA/#RRGGBB/#RRGGBBAA.",
      -        "type": "string"
      -      },
      -      "x": {
      -        "maximum": 255,
      -        "minimum": 0,
      -        "type": "integer"
      -      },
      -      "y": {
      -        "maximum": 255,
      -        "minimum": 0,
      -        "type": "integer"
      -      }
      -    },
      -    "required": [
      -      "x",
      -      "y",
      -      "color"
      -    ],
      -    "type": "object"
      -  },
      -  "rows": {
      -    "description": "Equal-width text rows. Every character is a palette key; dot and space skip a pixel.",
      -    "items": {
      -      "maxLength": 256,
      -      "minLength": 1,
      -      "type": "string"
      -    },
      -    "maxItems": 256,
      -    "minItems": 1,
      -    "type": "array"
      -  }
      -}
    • removedInput schema / properties / project / additionalProperties
      Removed value: -false
    • addedInput schema / properties / project / description
      Added value: +"A version-1 Pixelbolt recipe: {\"version\": 1, \"name\", \"width\", \"height\", \"palette\", \"symbols\"?, \"frames\": [{\"name\", \"duration\"?, \"from\"?, \"ops\"?, \"layers\"?}], \"animations\"?}. pixel_help explains it; its topic schema is the full JSON Schema. Mistakes come back with their exact path."
    • removedInput schema / properties / project / properties
      Removed value: -{
      -  "$schema": {
      -    "type": "string"
      -  },
      -  "anchor": {
      -    "description": "Default pivot for every frame, exported to the atlas as anchor (exported pixels) and pivot (anchor / source size).",
      -    "items": {
      -      "maximum": 4096,
      -      "minimum": -4096,
      -      "type": "integer"
      -    },
      -    "maxItems": 2,
      -    "minItems": 2,
      -    "type": "array"
      -  },
      -  "animations": {
      -    "additionalProperties": {
      -      "additionalProperties": false,
      -      "properties": {
      -        "direction": {
      -          "enum": [
      -            "forward",
      -            "reverse",
      -            "pingpong"
      -          ]
      -        },
      -        "frames": {
      -          "items": {
      -            "description": "Portable name: do not use Windows device names (CON, PRN, AUX, NUL, COM1–9, LPT1–9). Frame/animation names must be unique ignoring case.",
      -            "pattern": "^[a-zA-Z][a-zA-Z0-9_-]{0,63}$",
      -            "type": "string"
      -          },
      -          "maxItems": 1024,
      -          "minItems": 1,
      -          "type": "array"
      -        },
      -        "loop": {
      -          "type": "boolean"
      -        }
      -      },
      -      "required": [
      -        "frames"
      -      ],
      -      "type": "object"
      -    },
      -    "description": "ZIP32 bundle budget: animation count + frame count + 7 support files must not exceed 65,535.",
      -    "maxProperties": 65527,
      -    "minProperties": 1,
      -    "propertyNames": {
      -      "description": "Portable name: do not use Windows device names (CON, PRN, AUX, NUL, COM1–9, LPT1–9). Frame/animation names must be unique ignoring case.",
      -      "pattern": "^[a-zA-Z][a-zA-Z0-9_-]{0,63}$",
      -      "type": "string"
      -    },
      -    "type": "object"
      -  },
      -  "background": {
      -    "description": "Palette name, transparent, or #RGB/#RGBA/#RRGGBB/#RRGGBBAA.",
      -    "type": "string"
      -  },
      -  "frames": {
      -    "items": {
      -      "$ref": "#/$defs/frame"
      -    },
      -    "maxItems": 256,
      -    "minItems": 1,
      -    "type": "array"
      -  },
      -  "height": {
      -    "maximum": 256,
      -    "minimum": 1,
      -    "type": "integer"
      -  },
      -  "name": {
      -    "description": "Portable name: do not use Windows device names (CON, PRN, AUX, NUL, COM1–9, LPT1–9). Frame/animation names must be unique ignoring case.",
      -    "pattern": "^[a-zA-Z][a-zA-Z0-9_-]{0,63}$",
      -    "type": "string"
      -  },
      -  "palette": {
      -    "additionalProperties": {
      -      "pattern": "^(transparent|#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8}))$",
      -      "type": "string"
      -    },
      -    "maxProperties": 257,
      -    "properties": {
      -      "$ref": {
      -        "description": "Shared palette file, resolved by the CLI and MCP relative to this recipe. Local entries add to or override it.",
      -        "type": "string"
      -      }
      -    },
      -    "type": "object"
      -  },
      -  "ramps": {
      -    "description": "Palette keys from dark to light, one list per material. shade and scene ramp lighting move a colour along its ramp instead of inventing one. A key belongs to one ramp. A shared palette file ({\"palette\": {...}, \"ramps\": [...]}) can supply them.",
      -    "items": {
      -      "items": {
      -        "maxLength": 64,
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "maxItems": 32,
      -      "minItems": 2,
      -      "type": "array"
      -    },
      -    "maxItems": 64,
      -    "type": "array"
      -  },
      -  "sheet": {
      -    "additionalProperties": false,
      -    "properties": {
      -      "columns": {
      -        "maximum": 256,
      -        "minimum": 1,
      -        "type": "integer"
      -      },
      -      "padding": {
      -        "maximum": 16,
      -        "minimum": 0,
      -        "type": "integer"
      -      },
      -      "scale": {
      -        "maximum": 16,
      -        "minimum": 1,
      -        "type": "integer"
      -      },
      -      "trim": {
      -        "description": "Pack each frame by its visible bounds; the atlas reports trimmed rectangles with spriteSourceSize. Ignores columns.",
      -        "type": "boolean"
      -      }
      -    },
      -    "required": [],
      -    "type": "object"
      -  },
      -  "symbols": {
      -    "additionalProperties": {
      -      "$ref": "#/$defs/rows"
      -    },
      -    "propertyNames": {
      -      "description": "Portable name: do not use Windows device names (CON, PRN, AUX, NUL, COM1–9, LPT1–9). Frame/animation names must be unique ignoring case.",
      -      "pattern": "^[a-zA-Z][a-zA-Z0-9_-]{0,63}$",
      -      "type": "string"
      -    },
      -    "type": "object"
      -  },
      -  "version": {
      -    "const": 1
      -  },
      -  "width": {
      -    "maximum": 256,
      -    "minimum": 1,
      -    "type": "integer"
      -  }
      -}
    • removedInput schema / properties / project / required
      Removed value: -[
      -  "version",
      -  "name",
      -  "width",
      -  "height",
      -  "frames"
      -]
    • removedInput schema / properties / project / title
      Removed value: -"Pixelbolt project"
  3. First observedv0.9.0

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no output schema, the description carries the useful load of disclosing what comes back: revision id, size, frame timing, animations and clipping, and that no images or files are returned. It does not reconcile the non-read-only annotation (readOnlyHint=false) with what appears to be a check operation, leaving the persistence side-effect undefined.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences with the purpose front-loaded and the return-surface summary second. Nothing is redundant and no sentence could be dropped without losing information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-required-parameter tool with a nested recipe object and no output schema, the description covers purpose, workflow placement and return contents adequately. The remaining gap is behavioral: it never says whether validating persists or mutates anything, which matters given readOnlyHint=false.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with detailed descriptions for fps, the nested project recipe and the revision id alternative, so the schema does the heavy lifting. The description adds only an indirect hint ('its revision id') linking the revision parameter to a prior response; the fps grid-checking behavior lives entirely in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource ('Check a pixel art recipe for mistakes') and scopes it to a pre-inspection/pre-export gate, which separates it from siblings like pixel_render and pixel_compile. It stops short of naming those siblings directly, so the differentiation is suggestive rather than explicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Before inspecting or exporting it' states the point in the workflow where this tool applies, giving the agent a clear usage context. It does not name the alternative tools or call out when validation can or should be skipped, so it is clear but not exhaustive.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.