# Ferrous Solitaire

A cross-platform Klondike Solitaire game written in Rust, with a card-theme
system, full progression (XP / levels / achievements / daily challenges), and
optional self-hosted sync so your stats follow you across machines.

## Features

- **Klondike Solitaire** — Draw One and Draw Three modes; foundations are
  unlocked (any Ace lands in any empty slot, the slot then claims that suit)
- **Card themes** — bundled hayeah/playing-cards-assets default plus
  user-installable themes (drop a directory under the data dir or import a
  zip from Settings → Cosmetic)
- **Modern HUD** — reserved top band keeps cards from crowding the score
  readout; the action bar auto-fades when the cursor leaves it so it can't
  compete with the play surface
- **Drag feel** — every legal drop target is highlighted in green during
  drag; cards cast a soft drop shadow that lifts when picked up; the stock
  pile shows a remaining-count chip so you can see how close you are to a
  recycle
- **Keyboard navigation** — Tab cycles focus through buttons, arrow keys
  move within picker rows, Enter activates; works across every modal and
  the HUD action bar
- **Progression** — XP, levels, unlockable card backs and backgrounds
- **19 Achievements** — including secret ones
- **Daily Challenge** — server-seeded so every player worldwide gets the
  same deal
- **Leaderboard** — opt-in, powered by your own self-hosted server
- **Special Modes** (unlocked at level 5): Zen, Time Attack, Challenge
- **Sync** — pull/push stats across devices via a self-hosted server
- **Color-blind mode** — blue tint on red-suit cards alongside the suit
  glyph

## Android Install

### Obtainium (recommended — automatic updates)

1. Install [Obtainium](https://github.com/ImranR98/Obtainium/releases) on your device
2. Tap the badge below on your Android device — the source type is pre-configured, no manual selection needed:

   [<img src="https://raw.githubusercontent.com/ImranR98/Obtainium/main/assets/graphics/badge_obtainium.png" alt="Get it on Obtainium" height="40">](https://apps.obtainium.imranr.dev/redirect?r=obtainium://app/%7B%22id%22%3A%22com.ferrousapp.solitaire%22%2C%22url%22%3A%22https%3A//git.aleshym.co/funman300/Ferrous-Solitaire%22%2C%22author%22%3A%22funman300%22%2C%22name%22%3A%22Ferrous%20Solitaire%22%2C%22installedVersion%22%3Anull%2C%22latestVersion%22%3Anull%2C%22apkUrls%22%3A%22%5B%5D%22%2C%22preferredApkIndex%22%3A0%2C%22additionalSettings%22%3A%22%7B%7D%22%2C%22lastUpdateCheck%22%3Anull%2C%22pinned%22%3Afalse%2C%22categories%22%3A%5B%5D%2C%22releaseDate%22%3Anull%2C%22changeLog%22%3Anull%2C%22overrideSource%22%3A%22Codeberg%22%2C%22allowIdChange%22%3Afalse%2C%22otherAssetUrls%22%3A%22%5B%5D%22%7D)

3. Tap **Install** to download the current release — Obtainium will notify you when updates are available.

### Direct APK

Download the latest `ferrous-solitaire.apk` from the
[Releases](https://git.aleshym.co/funman300/Ferrous-Solitaire/releases) page,
enable **Install from unknown sources** in your device settings, and open the file.

## Building

**Prerequisites**

- Rust stable toolchain (`rustup install stable`)
- Linux: `libasound2-dev libudev-dev libxkbcommon-dev`
- macOS: Xcode Command Line Tools

```bash
# Fast development build
cargo run -p solitaire_app --features bevy/dynamic_linking

# Release build
cargo build -p solitaire_app --release
./target/release/solitaire_app
```

## Controls

Every action also has a visible UI button — keyboard shortcuts are optional
accelerators.

| Key | Action |
|---|---|
| Left click / drag | Move cards |
| Double click | Auto-move card to its best legal destination |
| Right click | Highlight legal moves for a card |
| Space / D | Draw from stock |
| U | Undo |
| H | Hint (highlight a legal move) |
| N | New game |
| Z | Zen mode |
| G | Forfeit (during pause) |
| Tab / Shift+Tab | Cycle keyboard focus |
| Enter | Activate focused button / auto-complete (when badge is lit) |
| Esc | Pause / dismiss modal |
| F1 | Help / controls |
| F11 | Toggle fullscreen |
| S / A / P / O / L / M | Stats / Achievements / Profile / Settings / Leaderboard / Menu |

## Card themes

The default theme ships embedded in the binary, so the game runs
self-contained with no external assets. To install another theme, drop a
directory containing a `theme.ron` manifest plus 53 SVG files (52 faces +
1 back) under the platform data dir's `themes/` folder, or import a zip
from **Settings → Cosmetic**. The picker chip lights up the moment a new
theme is registered. Themes are SVG-based, so they rasterise cleanly at
whatever resolution the window happens to be.

## Sync Server (optional)

To sync stats across machines, run the self-hosted server. See
[README_SERVER.md](README_SERVER.md) for setup instructions.

Once the server is running, open **Settings → Sync Backend**, enter the
server URL and your username, and register an account from within the
game.

## Running Tests

```bash
# All tests (982 passing as of v0.11.0)
cargo test --workspace

# Just game logic (no display required)
cargo test -p solitaire_core -p solitaire_sync -p solitaire_data -p solitaire_server

# Lint
cargo clippy --workspace --all-targets -- -D warnings

# Browser e2e smoke (starts solitaire_server automatically)
cd solitaire_server/e2e
npm ci
npx playwright install chromium
npm test

# Seed-batch cycle regression gate (thresholded)
npm run review:cycles:regression

# Loop-aware candidate benchmark (writes test-results/cycle-candidate.json)
npm run review:cycles:candidate
```

For layered engine-vs-UI automation design (Rust unit tests, wasm debug-API
integration tests, and Playwright UI validation), see
[docs/testing-architecture.md](docs/testing-architecture.md).

For Quaternions (`klondike` / `card_game`) dependency upgrades, use
[`scripts/update_quaternions_deps.sh`](scripts/update_quaternions_deps.sh) and
the runbook in [docs/card-game-integration.md](docs/card-game-integration.md).

## Credits

Built on [Bevy](https://bevyengine.org/) and the wider Rust ecosystem
(Tokio, Axum, sqlx, Serde, kira, and many more). Card faces come from
[hayeah/playing-cards-assets](https://github.com/hayeah/playing-cards-assets)
(MIT, derived from the public-domain `vector-playing-cards` library); the
default card back is original work; the UI font is FiraMono-Medium (OFL).
All audio is synthesized programmatically by this project. See
[CREDITS.md](CREDITS.md) for the full list and license details.

## Changelog

See [CHANGELOG.md](CHANGELOG.md).

## License

MIT — see [LICENSE](LICENSE).
