chore: rename app from Solitaire Quest to Ferrous Solitaire

Replace all display-name occurrences across web pages, Rust source,
docs, and Cargo metadata. Update localStorage token key from sq_token
to fs_token. Tagline "Klondike Solitaire" retained as genre descriptor.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
funman300
2026-05-13 17:04:45 -07:00
parent ea58f5dd64
commit 8325bf6cf7
39 changed files with 56 additions and 56 deletions
+2 -2
View File
@@ -1,4 +1,4 @@
# Solitaire Quest — Architecture Document
# Ferrous Solitaire — Architecture Document
> **Version:** 1.3
> **Language:** Rust (Edition 2024)
@@ -34,7 +34,7 @@
## 1. Project Overview
Solitaire Quest is a cross-platform Klondike Solitaire game written in Rust, targeting macOS, Windows, and Linux desktops. It features a full progression system with XP, levels, achievements, daily challenges, and an optional self-hosted sync server so statistics and progress are available across all of a player's devices.
Ferrous Solitaire is a cross-platform Klondike Solitaire game written in Rust, targeting macOS, Windows, and Linux desktops. It features a full progression system with XP, levels, achievements, daily challenges, and an optional self-hosted sync server so statistics and progress are available across all of a player's devices.
### Sync Backend by Platform
+1 -1
View File
@@ -1,6 +1,6 @@
# Changelog
All notable changes to Solitaire Quest are documented here. The format is
All notable changes to Ferrous Solitaire are documented here. The format is
based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this
project follows [Semantic Versioning](https://semver.org/).
+3 -3
View File
@@ -1,6 +1,6 @@
# Credits
Solitaire Quest is MIT-licensed (see [LICENSE](LICENSE)). It is built on top of
Ferrous Solitaire is MIT-licensed (see [LICENSE](LICENSE)). It is built on top of
the work of many open-source projects and a small handful of third-party
assets. This file lists every component that ships in the binary or in the
`assets/` directory.
@@ -43,7 +43,7 @@ copyleft code is statically linked into the game binary.
| File(s) | Source | License |
|---|---|---|
| `solitaire_engine/assets/themes/default/{suit}_{rank}.svg` (52 SVGs) | [hayeah/playing-cards-assets](https://github.com/hayeah/playing-cards-assets) | MIT |
| `solitaire_engine/assets/themes/default/back.svg` | Original — Solitaire Quest | MIT (this project) |
| `solitaire_engine/assets/themes/default/back.svg` | Original — Ferrous Solitaire | MIT (this project) |
| `assets/cards/faces/{RANK}{SUIT}.png` (52 PNGs) | Pre-rendered from the same `playing-cards-assets` SVGs | MIT (passed through from hayeah) |
| `assets/cards/backs/back_0.png` `back_4.png` | Original — generated by `solitaire_assetgen::gen_art` | MIT (this project) |
@@ -107,6 +107,6 @@ Audio files are MIT-licensed alongside the rest of this project.
backs, every audio file) are original work covered by this project's MIT
license.
If you redistribute Solitaire Quest, you must ship this `CREDITS.md` and the
If you redistribute Ferrous Solitaire, you must ship this `CREDITS.md` and the
`LICENSE` file alongside the binary so the MIT (project + hayeah card art)
and OFL (FiraMono) notices remain visible to end users.
+1 -1
View File
@@ -1,4 +1,4 @@
# Solitaire Quest
# Ferrous Solitaire
A cross-platform Klondike Solitaire game written in Rust, with a card-theme
system, full progression (XP / levels / achievements / daily challenges), and
+1 -1
View File
@@ -1,4 +1,4 @@
# Solitaire Quest — Self-Hosting Guide
# Ferrous Solitaire — Self-Hosting Guide
## Prerequisites
+2 -2
View File
@@ -1,4 +1,4 @@
# Solitaire Quest — Session Handoff
# Ferrous Solitaire — Session Handoff
**Last updated:** 2026-05-12 — Leaderboard display name shipped (`03be4fc`). All commits pushed to origin.
@@ -150,7 +150,7 @@ Items missing from the doc:
## Resume prompt
```
You are a senior Rust + Bevy developer working on Solitaire Quest.
You are a senior Rust + Bevy developer working on Ferrous Solitaire.
Working directory: <Rusty_Solitaire clone path>.
Branch: master. v0.23.0 is the current version (HEAD: 03be4fc). Fully pushed.
+2 -2
View File
@@ -1,4 +1,4 @@
# Solitaire Quest — Session Handoff (ARCHIVED)
# Ferrous Solitaire — Session Handoff (ARCHIVED)
> **This file is from Phase 2 (2026-04-25, 242 tests). It is kept for historical
> reference only. The authoritative session handoff is at the repo root:
@@ -24,7 +24,7 @@ All seven Cargo crates created and compiling cleanly:
| `solitaire_engine` | Stub | Bevy ECS systems — all plugins added in Phase 3 |
| `solitaire_server` | Stub | Axum sync server — implemented in Phase 8C |
| `solitaire_gpgs` | Compile-time stub | Google Play Games bridge — Android only, JNI in Phase: Android |
| `solitaire_app` | Working | Opens blank Bevy window titled "Solitaire Quest" at 1280×800 |
| `solitaire_app` | Working | Opens blank Bevy window titled "Ferrous Solitaire" at 1280×800 |
Fast compile profiles, `assets/` directory structure, and `.env.example` are all in place.
+1 -1
View File
@@ -2,7 +2,7 @@
> **Date:** 2026-04-28
> **Author:** Claude Code
> **Scope:** Feasibility analysis for porting Solitaire Quest to Android using cargo-mobile2
> **Scope:** Feasibility analysis for porting Ferrous Solitaire to Android using cargo-mobile2
---
@@ -1,4 +1,4 @@
# Solitaire Quest — Phase 1 + 2: Workspace & Core Game Engine
# Ferrous Solitaire — Phase 1 + 2: Workspace & Core Game Engine
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
@@ -555,7 +555,7 @@ fn main() {
.add_plugins(
DefaultPlugins.set(WindowPlugin {
primary_window: Some(Window {
title: "Solitaire Quest".into(),
title: "Ferrous Solitaire".into(),
resolution: (1280.0, 800.0).into(),
..default()
}),
@@ -571,7 +571,7 @@ fn main() {
```bash
cargo run -p solitaire_app --features bevy/dynamic_linking
```
Expected: A blank Bevy window titled "Solitaire Quest" opens. Press Escape or close the window to exit. No panics or errors in the terminal.
Expected: A blank Bevy window titled "Ferrous Solitaire" opens. Press Escape or close the window to exit. No panics or errors in the terminal.
---
@@ -1210,7 +1210,7 @@ fn main() {
.add_plugins(
DefaultPlugins.set(WindowPlugin {
primary_window: Some(Window {
title: "Solitaire Quest".into(),
title: "Ferrous Solitaire".into(),
resolution: (1280.0, 800.0).into(),
..default()
}),
+1 -1
View File
@@ -11,7 +11,7 @@
### Infrastructure
- Two machines (or VMs) referred to as **Machine A** and **Machine B** throughout this runbook. Both must be able to reach the sync server over the network.
- A running Solitaire Quest sync server reachable at a known URL, e.g. `https://solitaire.example.com`. See `README_SERVER.md` for setup.
- A running Ferrous Solitaire sync server reachable at a known URL, e.g. `https://solitaire.example.com`. See `README_SERVER.md` for setup.
- Verify the server is live before starting:
```bash
+1 -1
View File
@@ -3,7 +3,7 @@
> **Why this exists.** The 24 mockups in this directory are mobile
> (390 × 844 logical, iPhone 14 Pro frame) with one exception
> (`home-menu-desktop.html`). The Stitch project that produced them
> is named "Solitaire Quest *Mobile* Redesign" — the mobile-first
> is named "Ferrous Solitaire *Mobile* Redesign" — the mobile-first
> framing was deliberate when the new Android target opened, but
> desktop is still the primary delivery surface. Porting the mobile
> mockups 1:1 would land a 390-px-wide column floating in the middle
+1 -1
View File
@@ -87,7 +87,7 @@ required = true
name = "android.permission.INTERNET"
[package.metadata.android.application]
label = "Solitaire Quest"
label = "Ferrous Solitaire"
# Launcher icon — references the density-bucketed mipmap resource above.
icon = "@mipmap/ic_launcher"
# `debuggable` defaults to false on release builds; cargo-apk flips it
+1 -1
View File
@@ -106,7 +106,7 @@ pub fn run() {
DefaultPlugins
.set(WindowPlugin {
primary_window: Some(Window {
title: "Solitaire Quest".into(),
title: "Ferrous Solitaire".into(),
// X11/Wayland WM_CLASS so taskbar managers group
// multiple windows of this app correctly.
name: Some("solitaire-quest".into()),
+1 -1
View File
@@ -1,4 +1,4 @@
//! Generates PNG assets for Solitaire Quest.
//! Generates PNG assets for Ferrous Solitaire.
//!
//! Produces:
//! - 52 card face PNGs (120×168) — one per card, with rank, suit symbol, and
+1 -1
View File
@@ -49,7 +49,7 @@ pub enum SyncBackend {
#[default]
#[serde(rename = "local")]
Local,
/// Sync with a self-hosted Solitaire Quest server.
/// Sync with a self-hosted Ferrous Solitaire server.
#[serde(rename = "solitaire_server")]
SolitaireServer {
/// Base URL of the server, e.g. `"https://solitaire.example.com"`.
+2 -2
View File
@@ -6,7 +6,7 @@
//! | Struct | Backend |
//! |---|---|
//! | [`LocalOnlyProvider`] | No-op; used when sync is disabled |
//! | [`SolitaireServerClient`] | Self-hosted Solitaire Quest server (JWT auth) |
//! | [`SolitaireServerClient`] | Self-hosted Ferrous Solitaire server (JWT auth) |
//!
//! Use [`provider_for_backend`] to obtain a `Box<dyn SyncProvider + Send + Sync>`
//! without matching on [`SyncBackend`] anywhere else in the codebase.
@@ -55,7 +55,7 @@ impl SyncProvider for LocalOnlyProvider {
// SolitaireServerClient
// ---------------------------------------------------------------------------
/// HTTP sync client for the self-hosted Solitaire Quest server.
/// HTTP sync client for the self-hosted Ferrous Solitaire server.
///
/// Authenticates via JWT stored in the OS keychain. On a 401 response the
/// client automatically attempts a token refresh and retries the request once
+1 -1
View File
@@ -1,4 +1,4 @@
//! SVG builder for the Solitaire Quest application icon.
//! SVG builder for the Ferrous Solitaire application icon.
//!
//! Renders the project's signature `▌RS` Terminal mark (the same
//! cursor-block + monogram pair used on the splash boot-screen and
+1 -1
View File
@@ -1,4 +1,4 @@
//! Bevy integration layer for Solitaire Quest.
//! Bevy integration layer for Ferrous Solitaire.
#[cfg(target_os = "android")]
pub mod android_clipboard;
+3 -3
View File
@@ -9,7 +9,7 @@
//!
//! Slides:
//!
//! 1. **Welcome** — brief introduction to Solitaire Quest.
//! 1. **Welcome** — brief introduction to Ferrous Solitaire.
//! 2. **How to play** — drag-and-drop, double-click, and right-click hints.
//! 3. **Keyboard shortcuts** — a summary pulled from the same canonical list
//! used in `HelpScreen`. Accelerators: `Esc` anywhere in the flow skips
@@ -292,10 +292,10 @@ fn spawn_slide(commands: &mut Commands, index: u8, font_res: Option<&FontResourc
/// Slide 1 — Welcome.
fn spawn_slide_welcome(commands: &mut Commands, font_res: Option<&FontResource>) {
spawn_modal(commands, OnboardingScreen, Z_ONBOARDING, |card| {
spawn_modal_header(card, "Welcome to Solitaire Quest", font_res);
spawn_modal_header(card, "Welcome to Ferrous Solitaire", font_res);
spawn_modal_body_text(
card,
"Solitaire Quest is a free, offline-first Klondike Solitaire game. \
"Ferrous Solitaire is a free, offline-first Klondike Solitaire game. \
Play classic draw-1 or draw-3 Klondike, earn XP, unlock achievements, \
and compete on the leaderboard. Your progress is saved locally \
optional sync to your own server keeps it in step across all your devices.",
+2 -2
View File
@@ -2343,7 +2343,7 @@ fn sync_row(
row,
SettingsButton::ConnectSync,
"Connect",
"Connect to a self-hosted Solitaire Quest sync server.".to_string(),
"Connect to a self-hosted Ferrous Solitaire sync server.".to_string(),
button_font,
);
}
@@ -2920,7 +2920,7 @@ mod tests {
.expect("Connect button should spawn with a Tooltip when backend is Local");
assert_eq!(
connect_tip.as_ref(),
"Connect to a self-hosted Solitaire Quest sync server.",
"Connect to a self-hosted Ferrous Solitaire sync server.",
"ConnectSync tooltip must use the canonical microcopy"
);
}
+3 -3
View File
@@ -2,7 +2,7 @@
//!
//! On app start the engine spawns a fullscreen, high-Z overlay that
//! reads the Terminal-style "boot screen" — an accent-coloured cursor block, the
//! "Solitaire Quest" wordmark, a short fixture boot log, a progress
//! "Ferrous Solitaire" wordmark, a short fixture boot log, a progress
//! bar, and a footer with the design-system palette swatches and the
//! build version. The overlay fades in over 300 ms, holds for ~1 s,
//! then fades out for 300 ms before despawning. The deal animation
@@ -383,7 +383,7 @@ fn spawn_header_section(parent: &mut ChildSpawnerCommands, font_handle: &Handle<
));
hdr.spawn((
SplashFadable { base_color: TEXT_PRIMARY },
Text::new("Solitaire Quest"),
Text::new("Ferrous Solitaire"),
title_font,
TextColor(transparent(TEXT_PRIMARY)),
));
@@ -1170,7 +1170,7 @@ mod tests {
"expected the cursor block (▌) on the splash, got: {texts:?}"
);
assert!(
texts.iter().any(|t| t == "Solitaire Quest"),
texts.iter().any(|t| t == "Ferrous Solitaire"),
"expected the wordmark on the splash, got: {texts:?}"
);
assert!(
+1 -1
View File
@@ -1,4 +1,4 @@
//! Backend-agnostic sync plugin for Solitaire Quest.
//! Backend-agnostic sync plugin for Ferrous Solitaire.
//!
//! On startup, the plugin spawns an async pull task on [`AsyncComputeTaskPool`]
//! that fetches the remote payload from the active [`SyncProvider`]. Once the
+1 -1
View File
@@ -84,7 +84,7 @@ mod tests {
ThemeMeta {
id: "default".into(),
name: "Default".into(),
author: "Solitaire Quest".into(),
author: "Ferrous Solitaire".into(),
version: "1.0.0".into(),
card_aspect: (2, 3),
}
+1 -1
View File
@@ -268,7 +268,7 @@ mod tests {
let meta = ThemeMeta {
id: "default".into(),
name: "Default".into(),
author: "Solitaire Quest".into(),
author: "Ferrous Solitaire".into(),
version: "1.0.0".into(),
card_aspect: (2, 3),
};
+1 -1
View File
@@ -115,7 +115,7 @@ fn default_entry() -> ThemeEntry {
meta: ThemeMeta {
id: "default".to_string(),
name: "Default".to_string(),
author: "Solitaire Quest".to_string(),
author: "Ferrous Solitaire".to_string(),
version: "1.0".to_string(),
card_aspect: (2, 3),
},
+1 -1
View File
@@ -1,6 +1,6 @@
//! Keyboard focus ring for modal buttons (Phase 1).
//!
//! Solitaire Quest's 11 modals (Help, Stats, Achievements, Settings,
//! Ferrous Solitaire's 11 modals (Help, Stats, Achievements, Settings,
//! Profile, Leaderboard, Pause, Forfeit confirm, GameOver, Confirm new
//! game, Onboarding) ship without any keyboard focus support. Phase 1
//! gives every button spawned via [`crate::ui_modal::spawn_modal_button`]
+1 -1
View File
@@ -1,4 +1,4 @@
//! Solitaire Quest sync server library.
//! Ferrous Solitaire sync server library.
//!
//! Exposes [`build_router`] so integration tests can construct the full Axum
//! application against an in-memory SQLite database without starting a real
+1 -1
View File
@@ -1,4 +1,4 @@
//! Solitaire Quest sync server entry point.
//! Ferrous Solitaire sync server entry point.
//!
//! Reads configuration from environment variables (via `dotenvy`), initialises
//! the SQLite database, runs migrations, then starts the Axum HTTP server.
+1 -1
View File
@@ -1,4 +1,4 @@
/* Solitaire Quest interactive game page.
/* Ferrous Solitaire interactive game page.
Palette mirrors the Bevy app's Terminal (base16-eighties) design system.
Card faces/backs are PNG images served from /assets/cards/. */
+2 -2
View File
@@ -3,14 +3,14 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Solitaire Quest — Play</title>
<title>Ferrous Solitaire — Play</title>
<link rel="stylesheet" href="/web/game.css">
</head>
<body>
<header>
<div class="hud-left">
<a href="/" class="home-link" title="Home">&#8592;</a>
<span class="logo">Solitaire Quest</span>
<span class="logo">Ferrous Solitaire</span>
<span id="hud-seed" class="muted"></span>
</div>
<div class="hud-center">
+1 -1
View File
@@ -1,4 +1,4 @@
// Solitaire Quest — interactive browser game.
// Ferrous Solitaire — interactive browser game.
//
// Architecture:
// - `SolitaireGame` (Rust/WASM via solitaire_core) owns all rule logic.
+2 -2
View File
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Solitaire Quest</title>
<title>Ferrous Solitaire</title>
<style>
@font-face {
font-family: "FiraMono";
@@ -119,7 +119,7 @@
</style>
</head>
<body>
<div class="logo">Solitaire Quest</div>
<div class="logo">Ferrous Solitaire</div>
<div class="tagline">Klondike Solitaire</div>
<nav class="cards">
+2 -2
View File
@@ -3,12 +3,12 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Solitaire Quest — Replay</title>
<title>Ferrous Solitaire — Replay</title>
<link rel="stylesheet" href="/web/replay.css">
</head>
<body>
<header>
<h1>Solitaire Quest <span class="muted">— Replay</span></h1>
<h1>Ferrous Solitaire <span class="muted">— Replay</span></h1>
<div id="caption" class="muted">Loading…</div>
</header>
+2 -2
View File
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Solitaire Quest — Leaderboard</title>
<title>Ferrous Solitaire — Leaderboard</title>
<style>
@font-face {
font-family: "FiraMono";
@@ -99,7 +99,7 @@
</table>
</main>
<script>
const TOKEN_KEY = 'sq_token';
const TOKEN_KEY = 'fs_token';
function fmtTime(secs) {
if (!secs) return '—';
const m = Math.floor(secs / 60), s = secs % 60;
+1 -1
View File
@@ -1,4 +1,4 @@
/* Solitaire Quest replay viewer Terminal (base16-eighties) palette,
/* Ferrous Solitaire replay viewer Terminal (base16-eighties) palette,
matching the Bevy desktop/Android app's ui_theme.rs tokens exactly. */
:root {
+1 -1
View File
@@ -1,4 +1,4 @@
// Solitaire Quest replay viewer.
// Ferrous Solitaire replay viewer.
//
// Pulls the replay JSON from `/api/replays/:id`, hands it to the
// `solitaire_wasm` ReplayPlayer (which owns a real solitaire_core
+1 -1
View File
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Solitaire Quest — Recent Replays</title>
<title>Ferrous Solitaire — Recent Replays</title>
<style>
@font-face {
font-family: "FiraMono";
+1 -1
View File
@@ -1,4 +1,4 @@
//! Shared API types and merge logic for Solitaire Quest.
//! Shared API types and merge logic for Ferrous Solitaire.
//!
//! This crate is the contract between the game client (`solitaire_data`) and
//! the sync server (`solitaire_server`). Changing any public type here is a