An atproto AppView for tracking a Magic: The Gathering collection github.com/eth0net/manaweb
appview atproto mtg rust typescript
TypeScript 58%
Rust 39%
CSS 2%
Just 1%
Dockerfile <1%
JavaScript <1%
HTML <1%
Shell <1%
<1%

README.md

Manaweb #

An atproto AppView for tracking a Magic: The Gathering collection — your cards live as records in your own PDS, not in someone else's database.

MTG-first. Collection tracking now; scanner, valuation, deck building and a game toolkit later.

Status #

Pre-v0, and it runs end to end. crates/scryfall streams Scryfall's bulk data, crates/core shreds every paper printing into SQLite, and the manaweb binary exports the catalog a browser needs and uploads it. The client signs in over OAuth, reads and writes records in your own PDS, imports a ManaBox CSV, and searches the catalog offline with most of Scryfall's query syntax. A tab holds a camera over a card and reads which printing it is against an index built from Scryfall's own artwork, though a scan lands nowhere yet. The lexicons are validated against atproto's own implementation in CI, along with the OAuth client metadata document.

Not there yet: pricing, decks and Explore. See the roadmap.

Stack #

  • Rust workspace — axum API, SQLite and a Scryfall bulk-data sync, all in one binary. The Jetstream firehose consumer arrives with Explore.
  • TypeScript PWA in web/, built with Bun and deployed to a CDN alongside the catalog artifact. Nothing a browser fetches comes from the binary.

Layout #

manaweb/
  crates/
    api/                 routes and handlers
    appview/             the `manaweb` binary
    artwork/             pulls Scryfall's art and hashes it for the index
    core/                card cache, and the catalog it exports
    objects/             the bucket, and the `manaweb-upload` tool
    scanner/             reading a card out of a frame, shared with the browser
    scryfall/            bulk-data fetch/parse
  docs/                  roadmap, and the reasoning behind each decision
  fixtures/              records that seed a dev account
  lexicons/              NSID JSON schemas
  tools/                 checks that span both sides, and the seeder
  web/                   the client, and its OAuth client metadata document

just --list is the whole workflow. Configuration lists what the binary and the tools read from the environment.

Running it #

The server needs no arguments and reads its configuration from the environment — configuration.md lists all of it.

docker run --rm -v manaweb-data:/data ghcr.io/eth0net/manaweb

Tagged X.Y.Z, X.Y and latest, published from the tag it was built at. docker build -t manaweb . builds the same image from a checkout.

Nothing has to be published: it syncs Scryfall, exports the catalog and uploads it, and the app and that catalog are served from elsewhere. Port 8080 carries /health, and the catalog for local development.

/data holds the card cache and the exported catalog, owned by uid 10001, so a bind mount has to be owned by that id to be writable. ENTRYPOINT is the binary and serve is the default command, so docker run manaweb version reaches a one-off without knowing where anything lives. manaweb health is the same door, and is what the container checks itself with.

From a checkout, just serve does the same thing without the container.

Contributing #

See CONTRIBUTING.md. Commits need a DCO sign-off (git commit -s); there's no CLA.

License #

The AppView is licensed under AGPL-3.0 — self-host it freely, but if you run a modified version as a network service, your users get the source.

lexicons/ is MIT instead. NSID schemas are shared vocabulary, and copyleft on a schema file would discourage the adoption that's the whole point of publishing them.

The icon is the spider web from Noto Emoji, Apache-2.0, recolored.

Card data and images come from Scryfall under the Wizards of the Coast Fan Content Policy. Manaweb is unofficial Fan Content permitted under the Fan Content Policy. Not approved or endorsed by Wizards. Portions of the materials used are property of Wizards of the Coast. ©Wizards of the Coast LLC.