sprite-catalog

The sprite catalog that drives trade matching and giveaways in the Sprites Trading HQ Discord server. One JSON file per season, validated against a JSON Schema.

This repo is data, not code. It is public so anyone can read it, build against it, or run their own bot from it.


Why JSON

The catalog is a public data source other people consume. JSON is readable in every language and in the browser with zero dependencies; YAML needs a parser everywhere.

JSON's one real weakness for a hand-maintained file is that it has no comments and is unforgiving about syntax. Both are covered: the schema in schema/ gives editors autocomplete and inline validation as you type, CI rejects malformed files before merge, and every object accepts a notes field for anything you would otherwise have written as a comment.


Layout

schema/sprite-catalog.schema.json   the contract — CI and editors both use it
seasons/c7s3.json                   one file per season, named for the season
seasons/c7s4.json

Season files are append-mostly. Entries are never deleted — a sprite that leaves circulation gets "status": "hidden", which drops it out of matching while keeping it in the inventories of everyone who already holds one.


Format

Variants nest under their base sprite so base_name and row_name aren't repeated for every skin. The bot flattens this to one row per variant on load.

{
  "season": "c7s3",
  "game_mode": "br",
  "cross_mode_trading": false,
  "sprites": [
    {
      "base_name": "Example Sprite",
      "row_name": "Example Row",
      "variants": [
        {
          "variant": "Default",
          "status": "released",
          "released_at": "2026-03-14",
          "max_stack": 5,
          "confirmed": true
        },
        {
          "variant": "Gold",
          "status": "unreleased",
          "notes": "Datamined; not yet obtainable in game."
        }
      ]
    }
  ]
}

The three statuses

Status Meaning
unreleased Known but not yet obtainable. Excluded from matching.
released Obtainable and tradeable.
hidden Dropped out of matching, retained in inventories. Reversible.

hidden deliberately replaces a retired concept that appeared in earlier drafts. Sprites usually come back, and if one never does, nothing is lost by having called it hidden — whereas retired implies a permanence the data can't promise.

Fields worth explaining

  • confirmed — variant lists are assumed-complete guesses until someone is actually recorded owning one. Unconfirmed variants are deprioritised in autocomplete and left out of the coverage metric, so a speculative entry can't quietly distort either.
  • rarity_weight — display and analytics only. The matcher does not read it. Rarity matching was removed on purpose: value-matching is how selfish players win and the pool starves. Trades are N-for-N by count, never by value.
  • max_stack — anything above 1 means spare copies can enter the give pool.
  • cross_mode_trading — defaults to false. Leave it there unless the policy is deliberately changed.

Contributing

  1. Fork or branch, edit the season file.
  2. Open a PR. CI validates every file in seasons/ against the schema and fails on malformed JSON, unknown fields, bad status values, or a season value that doesn't match the filename.
  3. A mod merges. The bot picks it up on the next /mod catalog reload, which shows a diff preview ("adds 6 sprites, 14 variants, no removals — apply?") before anything is written.

The bot's exporter opens a draft PR automatically when it sees a sprite ID it doesn't recognise, so most additions start here rather than being typed by hand.

Editor setup — point your editor at schema/sprite-catalog.schema.json and you get completion and error squiggles inline. In VS Code, add to .vscode/settings.json:

{
  "json.schemas": [
    { "fileMatch": ["seasons/*.json"], "url": "./schema/sprite-catalog.schema.json" }
  ]
}

Consuming it

The bot fetches raw files over HTTP and caches them in memory — autocomplete has a hard 3-second budget with no defer available, so it never queries a database per keystroke.

The raw URL is configurable via CATALOG_REPO_RAW, so you can point a development bot at your own fork without touching code:

CATALOG_REPO_RAW=https://git.thewichersfamily.com/thethreemagi/sprite-catalog/raw/branch/main

Nothing about the format is bot-specific. Fetch the JSON and use it however you like.


Note on history

Commits here carry no AI attribution — see .githooks/commit-msg, enabled with git config core.hooksPath .githooks after cloning. The hook ships executable; Git just never turns a repo's hooks on by itself. Please keep it that way in PRs.

S
Description
Public sprite catalog data — one JSON file per season, with a JSON Schema and validation CI. Consumed by sprite-trade-bot via a configurable raw URL.
Readme
43 KiB
Languages
Python 80.6%
Shell 19.4%