# 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/`](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. ```json { "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 { "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`](.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.