diff --git a/README.md b/README.md index b8644a4..fe6ba81 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,143 @@ # sprite-catalog -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. \ No newline at end of file +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 && chmod +x .githooks/commit-msg`. +Please keep it that way in PRs.