# mtgc — Personal Magic: The Gathering Library Catalog A desktop app (Tauri v2 + React) for cataloging your MTG collection: rapid fuzzy card entry, rich criteria search (colors, commander color-identity compatibility, mana value, type/subtype/keyword), and deck organization with per-card deck membership. Built so the eventual mobile port is cheap — all logic lives in a platform-agnostic Rust core. ## Architecture ``` src/ React + TypeScript UI (swappable presentation) src-tauri/ Tauri v2 shell — exposes the core as typed commands crates/mtgc-core/ Pure Rust: db, fuzzy search, filters, decks, ingester ``` Two SQLite databases, joined at runtime via `ATTACH`: - **`reference.db`** — read-only card data built from Scryfall bulk. Bulky, re-downloadable per device, **not synced**. - **`library.db`** — your owned cards + decks. Small, portable, **the file you sync** (drop it in Syncthing/Dropbox/Nextcloud). Point the app at it via *Choose library file…*. Both default to the OS app-data dir (e.g. `~/.local/share/com.garrettmills.mtgc/`). ## First-time setup ```bash ./scripts/devel-setup.sh # Tauri system libs (webkit2gtk/gtk3) + Tauri CLI npm install # frontend deps ``` > **Why GTK3, not GTK4?** Tauri v2's Linux backend (`wry`/`tao`) hard-depends on > GTK3 + `webkit2gtk-4.1`; there's no GTK4/webkitgtk-6.0 option yet. GTK4 support is > tracked upstream but unmerged with no ETA: > [tauri#7335](https://github.com/tauri-apps/tauri/issues/7335), > [tao#1104](https://github.com/tauri-apps/tao/pull/1104), > [wry#1228](https://github.com/tauri-apps/wry/issues/1228). Revisit once Tauri > ships GTK4 support (likely Tauri v3). ## Run ```bash cargo tauri dev # launches the desktop app (dev mode) ``` On first launch, click **Download card data** — it fetches the Scryfall *Oracle Cards* + *Default Cards* bulk (~a few hundred MB) and builds `reference.db`. After that the app is fully offline. You can also build the card database from the command line: ```bash cargo run -p mtgc-core --bin mtgc-ingest -- /path/to/reference.db ``` ## Production build Build an optimized app with the frontend embedded into the executable: ```bash ./scripts/devel-setup.sh # once, if not already done cargo tauri build ``` Outputs (under the workspace `target/release/`): - **`target/release/mtgc`** — the standalone executable. The web UI and all app logic are baked into this one file. It dynamically links the system WebKit/GTK libraries (`webkit2gtk4.1`, `gtk3`), so those must be present on the machine that runs it — they are on any modern desktop Linux and are installed by `devel-setup.sh`. - **`target/release/bundle/rpm/*.rpm`** and **`.../deb/*.deb`** — native installers (Fedora / Debian-based) that add a menu entry and icon. Useful variants: ```bash cargo tauri build --no-bundle # only the bare target/release/mtgc binary ``` Notes: - The `mtgc` binary is a single file but relies on the system WebKit/GTK libs being present (installed by `devel-setup.sh`). - The binary does **not** embed card data — first run still downloads the Scryfall bulk into the OS app-data dir, and your synced `library.db` lives there by default (override with *Choose library file…*). - The `[profile.release]` settings in `Cargo.toml` (strip + LTO) make the release build take a few minutes but keep the binary small. ## Using it - **Add Cards** — type a name (typos OK); ↑/↓ then Enter adds a copy. - **Library** — filter owned cards by name, colors, commander identity (color identity ⊆ chosen), mana value range, type/subtype/keyword, or deck. Hover a row's thumbnail for a full-size preview that tracks the cursor. Rows show which decks a card is in and a warning (⚠) when it's assigned to more decks than you own. Toggle **List / Tiles** (top-right) to switch between the table and a grid of full card images; the choice is remembered. - Deck contents offer the same List / Tiles toggle and hover previews. - **Decks** — create decks and assign owned cards; set per-deck quantities. ## Develop / test ```bash cargo test -p mtgc-core # core unit tests (db, search, filters, decks, ingest) npm run build # typecheck + build frontend cargo build # build everything incl. the desktop app ``` ## Android The Rust core and frontend are platform-agnostic, so the Android build shares all app logic with the desktop; only data provisioning differs. ### One-time setup Install Android Studio and **launch it once** so its wizard downloads the SDK, then: ```bash ./scripts/android-setup.sh ``` That adds what Android Studio doesn't install by default: the SDK command-line tools, a pinned stable **NDK**, and the Rust Android targets. It prints the three environment variables to export (`ANDROID_HOME`, `NDK_HOME`, `JAVA_HOME`). > **Why the NDK?** `mtgc-core` builds `rusqlite` with the `bundled` feature > (compiles SQLite from C) and `rustls` pulls in `ring` (C/asm), so a C > cross-toolchain is required. The bundled SQLite can't be swapped for > Android's system libsqlite3 either — the card schema needs FTS5 with the > `trigram` tokenizer, which platform SQLite often lacks. > **Why `JAVA_HOME`?** Gradle/AGP reject very new JDKs. The script prefers > Android Studio's bundled JetBrains Runtime (JDK 21), which needs no extra > install. ### Build and run Every Android command needs `ANDROID_HOME` / `NDK_HOME` / `JAVA_HOME`. Source the helper once per shell — it auto-detects all three: ```bash source scripts/android-env.sh # bash / zsh ``` ```fish source scripts/android-env.fish # fish ``` Only the env helper is shell-specific (it has to mutate the calling shell); `android-setup.sh` is executed rather than sourced, so it works from any shell. Then, from the project root: ```bash cargo tauri android dev --open # dev server + open in Android Studio cargo tauri android build --apk # standalone release APK ``` `src-tauri/gen/android` is committed (unlike the rest of `gen/`) because `AndroidManifest.xml` is hand-edited — Android permissions have no `tauri.conf.json` equivalent. ### Working in Android Studio Use **`cargo tauri android dev --open`** rather than opening `src-tauri/gen/android` directly. Studio's Run button delegates the Rust build to `cargo tauri android android-studio-script`, which expects a running Tauri dev session — it reads the dev-server address from `/tmp/-server-addr`. Open the Gradle project on its own and the build fails with `failed to read missing addr file`. With the dev session running, Studio's device dropdown, Device Manager (emulator), and debugger all work normally. > **JetBrains Toolbox users:** `--open` finds Studio by scanning XDG data dirs > for a `.desktop` entry whose `Name` is *exactly* `Android Studio`. Toolbox > writes a versioned name instead (e.g. `Android Studio Quail 2 2026.1.2 Patch > 1`), so the lookup misses and the launch fails with a confusing > `Cmd(["Android Studio"]) ... No such file or directory`. `android-setup.sh` > drops in a hidden shim entry (`~/.local/share/applications/android-studio.desktop`) > to fix this; delete that file to undo it. To build without Studio and without a dev server, use `cargo tauri android build` — that path needs no addr file. ### Card data on a phone Downloading card data streams ~740MB of JSON to build a ~73MB database, which is slow on mobile and may be killed if the app is backgrounded. Faster: copy `reference.db` from a desktop install onto the device and use **Import card data…**. The file is validated before it replaces anything. ## Branding The logo is an original pirate-ship silhouette in the terracotta brand color (`#C8553D`) — a nod to the MTG card "Pirate Ship", not a reproduction of its art. Source: `src-tauri/icons/logo-source.svg`. To regenerate the full platform icon set after editing it: ```bash cargo tauri icon src-tauri/icons/logo-source.svg ```