Add JSON Schema for season catalog files

This commit is contained in:
2026-07-31 17:48:46 +01:00
parent 8890e42210
commit 295d594936
+108
View File
@@ -0,0 +1,108 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://git.thewichersfamily.com/thethreemagi/sprite-catalog/raw/branch/main/schema/sprite-catalog.schema.json",
"title": "Sprite catalog season file",
"description": "One file per season. Variants are nested under their base sprite to avoid repeating base_name and row_name; the bot flattens them to one row per variant on load.",
"type": "object",
"additionalProperties": false,
"required": ["season", "game_mode", "sprites"],
"properties": {
"season": {
"type": "string",
"pattern": "^c[0-9]+s[0-9]+$",
"description": "Season identifier, e.g. c7s3. Must match the filename stem."
},
"game_mode": {
"$ref": "#/$defs/gameMode",
"description": "Default game mode for every sprite in this file. Individual sprites may override it."
},
"cross_mode_trading": {
"type": "boolean",
"default": false,
"description": "Whether sprites from different game modes may be matched against each other. Defaults to false; leave it false unless the policy is deliberately changed."
},
"notes": {
"type": "string",
"description": "Free text. JSON has no comments, so anything you would have written as one goes here."
},
"sprites": {
"type": "array",
"minItems": 1,
"items": { "$ref": "#/$defs/sprite" }
}
},
"$defs": {
"gameMode": {
"type": "string",
"enum": ["br", "og", "reload", "festival", "rocket_racing", "lego"],
"description": "Extend this list rather than inventing values; the bot validates against it."
},
"status": {
"type": "string",
"enum": ["unreleased", "released", "hidden"],
"description": "unreleased: known but not yet obtainable. released: obtainable and tradeable. hidden: dropped out of matching but retained in inventories, and reversible — most hidden sprites come back."
},
"sprite": {
"type": "object",
"additionalProperties": false,
"required": ["base_name", "row_name", "variants"],
"properties": {
"base_name": {
"type": "string",
"minLength": 1,
"description": "The sprite's base name, shared across its variants. Unique within a season."
},
"row_name": {
"type": "string",
"minLength": 1,
"description": "The collection row this sprite belongs to. Autocomplete matches on this as well as base_name."
},
"game_mode": {
"$ref": "#/$defs/gameMode",
"description": "Overrides the season-level game_mode for this sprite only."
},
"notes": { "type": "string" },
"variants": {
"type": "array",
"minItems": 1,
"items": { "$ref": "#/$defs/variant" }
}
}
},
"variant": {
"type": "object",
"additionalProperties": false,
"required": ["variant", "status"],
"properties": {
"variant": {
"type": "string",
"minLength": 1,
"description": "Variant name, unique within its base sprite. Use \"Default\" when a sprite has only one form."
},
"status": { "$ref": "#/$defs/status" },
"released_at": {
"type": "string",
"format": "date",
"description": "ISO 8601 date. Required in practice once status is released; omit while unreleased."
},
"max_stack": {
"type": "integer",
"minimum": 1,
"default": 1,
"description": "Maximum copies a member can hold. Anything above 1 can enter the give pool as a spare."
},
"rarity_weight": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Retained for display and analytics only. The matcher does NOT use it — rarity matching was removed deliberately, because value-matching is how selfish players win and the pool starves."
},
"confirmed": {
"type": "boolean",
"default": false,
"description": "Flips true the first time a real member is recorded owning this variant. Unconfirmed entries are deprioritised in autocomplete and excluded from the coverage metric, since variant lists are assumed-complete guesses until proven."
},
"notes": { "type": "string" }
}
}
}
}