diff --git a/solitaire_engine/assets/themes/rusty-pixel/back.png b/solitaire_engine/assets/themes/rusty-pixel/back.png deleted file mode 100644 index ef19f35..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/back.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/clubs_10.png b/solitaire_engine/assets/themes/rusty-pixel/clubs_10.png deleted file mode 100644 index ec5e928..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/clubs_10.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/clubs_2.png b/solitaire_engine/assets/themes/rusty-pixel/clubs_2.png deleted file mode 100644 index b6eda9d..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/clubs_2.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/clubs_3.png b/solitaire_engine/assets/themes/rusty-pixel/clubs_3.png deleted file mode 100644 index 09a1df6..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/clubs_3.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/clubs_4.png b/solitaire_engine/assets/themes/rusty-pixel/clubs_4.png deleted file mode 100644 index f4be5c7..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/clubs_4.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/clubs_5.png b/solitaire_engine/assets/themes/rusty-pixel/clubs_5.png deleted file mode 100644 index 3526423..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/clubs_5.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/clubs_6.png b/solitaire_engine/assets/themes/rusty-pixel/clubs_6.png deleted file mode 100644 index ced4916..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/clubs_6.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/clubs_7.png b/solitaire_engine/assets/themes/rusty-pixel/clubs_7.png deleted file mode 100644 index 974518e..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/clubs_7.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/clubs_8.png b/solitaire_engine/assets/themes/rusty-pixel/clubs_8.png deleted file mode 100644 index 534e1b1..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/clubs_8.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/clubs_9.png b/solitaire_engine/assets/themes/rusty-pixel/clubs_9.png deleted file mode 100644 index ebd8e24..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/clubs_9.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/clubs_ace.png b/solitaire_engine/assets/themes/rusty-pixel/clubs_ace.png deleted file mode 100644 index f2c6da9..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/clubs_ace.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/clubs_jack.png b/solitaire_engine/assets/themes/rusty-pixel/clubs_jack.png deleted file mode 100644 index fe7ada4..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/clubs_jack.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/clubs_king.png b/solitaire_engine/assets/themes/rusty-pixel/clubs_king.png deleted file mode 100644 index 71772a6..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/clubs_king.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/clubs_queen.png b/solitaire_engine/assets/themes/rusty-pixel/clubs_queen.png deleted file mode 100644 index 1ecdc87..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/clubs_queen.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/diamonds_10.png b/solitaire_engine/assets/themes/rusty-pixel/diamonds_10.png deleted file mode 100644 index fe9dd6b..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/diamonds_10.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/diamonds_2.png b/solitaire_engine/assets/themes/rusty-pixel/diamonds_2.png deleted file mode 100644 index 5d80d50..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/diamonds_2.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/diamonds_3.png b/solitaire_engine/assets/themes/rusty-pixel/diamonds_3.png deleted file mode 100644 index 0834e1a..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/diamonds_3.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/diamonds_4.png b/solitaire_engine/assets/themes/rusty-pixel/diamonds_4.png deleted file mode 100644 index 921095f..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/diamonds_4.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/diamonds_5.png b/solitaire_engine/assets/themes/rusty-pixel/diamonds_5.png deleted file mode 100644 index d64d5e8..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/diamonds_5.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/diamonds_6.png b/solitaire_engine/assets/themes/rusty-pixel/diamonds_6.png deleted file mode 100644 index 7939893..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/diamonds_6.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/diamonds_7.png b/solitaire_engine/assets/themes/rusty-pixel/diamonds_7.png deleted file mode 100644 index 1c70eef..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/diamonds_7.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/diamonds_8.png b/solitaire_engine/assets/themes/rusty-pixel/diamonds_8.png deleted file mode 100644 index 3ad4103..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/diamonds_8.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/diamonds_9.png b/solitaire_engine/assets/themes/rusty-pixel/diamonds_9.png deleted file mode 100644 index 740bb8a..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/diamonds_9.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/diamonds_ace.png b/solitaire_engine/assets/themes/rusty-pixel/diamonds_ace.png deleted file mode 100644 index c68b50c..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/diamonds_ace.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/diamonds_jack.png b/solitaire_engine/assets/themes/rusty-pixel/diamonds_jack.png deleted file mode 100644 index aa979b1..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/diamonds_jack.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/diamonds_king.png b/solitaire_engine/assets/themes/rusty-pixel/diamonds_king.png deleted file mode 100644 index bfbc96f..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/diamonds_king.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/diamonds_queen.png b/solitaire_engine/assets/themes/rusty-pixel/diamonds_queen.png deleted file mode 100644 index 7b5b710..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/diamonds_queen.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/hearts_10.png b/solitaire_engine/assets/themes/rusty-pixel/hearts_10.png deleted file mode 100644 index d6fcc4b..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/hearts_10.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/hearts_2.png b/solitaire_engine/assets/themes/rusty-pixel/hearts_2.png deleted file mode 100644 index bdc2e0d..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/hearts_2.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/hearts_3.png b/solitaire_engine/assets/themes/rusty-pixel/hearts_3.png deleted file mode 100644 index 8b96ca7..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/hearts_3.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/hearts_4.png b/solitaire_engine/assets/themes/rusty-pixel/hearts_4.png deleted file mode 100644 index f016ef1..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/hearts_4.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/hearts_5.png b/solitaire_engine/assets/themes/rusty-pixel/hearts_5.png deleted file mode 100644 index dd2f719..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/hearts_5.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/hearts_6.png b/solitaire_engine/assets/themes/rusty-pixel/hearts_6.png deleted file mode 100644 index 05059c9..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/hearts_6.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/hearts_7.png b/solitaire_engine/assets/themes/rusty-pixel/hearts_7.png deleted file mode 100644 index c838716..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/hearts_7.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/hearts_8.png b/solitaire_engine/assets/themes/rusty-pixel/hearts_8.png deleted file mode 100644 index d15f453..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/hearts_8.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/hearts_9.png b/solitaire_engine/assets/themes/rusty-pixel/hearts_9.png deleted file mode 100644 index d444ecb..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/hearts_9.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/hearts_ace.png b/solitaire_engine/assets/themes/rusty-pixel/hearts_ace.png deleted file mode 100644 index 813fe94..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/hearts_ace.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/hearts_jack.png b/solitaire_engine/assets/themes/rusty-pixel/hearts_jack.png deleted file mode 100644 index 8814184..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/hearts_jack.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/hearts_king.png b/solitaire_engine/assets/themes/rusty-pixel/hearts_king.png deleted file mode 100644 index 346bb3c..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/hearts_king.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/hearts_queen.png b/solitaire_engine/assets/themes/rusty-pixel/hearts_queen.png deleted file mode 100644 index de59198..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/hearts_queen.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/spades_10.png b/solitaire_engine/assets/themes/rusty-pixel/spades_10.png deleted file mode 100644 index 6feda4e..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/spades_10.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/spades_2.png b/solitaire_engine/assets/themes/rusty-pixel/spades_2.png deleted file mode 100644 index 051f847..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/spades_2.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/spades_3.png b/solitaire_engine/assets/themes/rusty-pixel/spades_3.png deleted file mode 100644 index fab5b2c..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/spades_3.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/spades_4.png b/solitaire_engine/assets/themes/rusty-pixel/spades_4.png deleted file mode 100644 index 9947718..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/spades_4.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/spades_5.png b/solitaire_engine/assets/themes/rusty-pixel/spades_5.png deleted file mode 100644 index a0734c9..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/spades_5.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/spades_6.png b/solitaire_engine/assets/themes/rusty-pixel/spades_6.png deleted file mode 100644 index 7f5cb1e..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/spades_6.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/spades_7.png b/solitaire_engine/assets/themes/rusty-pixel/spades_7.png deleted file mode 100644 index 33dc34a..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/spades_7.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/spades_8.png b/solitaire_engine/assets/themes/rusty-pixel/spades_8.png deleted file mode 100644 index 5f2bdba..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/spades_8.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/spades_9.png b/solitaire_engine/assets/themes/rusty-pixel/spades_9.png deleted file mode 100644 index 8d136a2..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/spades_9.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/spades_ace.png b/solitaire_engine/assets/themes/rusty-pixel/spades_ace.png deleted file mode 100644 index 2316169..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/spades_ace.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/spades_jack.png b/solitaire_engine/assets/themes/rusty-pixel/spades_jack.png deleted file mode 100644 index 2b22d54..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/spades_jack.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/spades_king.png b/solitaire_engine/assets/themes/rusty-pixel/spades_king.png deleted file mode 100644 index 2b8aa99..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/spades_king.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/spades_queen.png b/solitaire_engine/assets/themes/rusty-pixel/spades_queen.png deleted file mode 100644 index a102105..0000000 Binary files a/solitaire_engine/assets/themes/rusty-pixel/spades_queen.png and /dev/null differ diff --git a/solitaire_engine/assets/themes/rusty-pixel/theme.ron b/solitaire_engine/assets/themes/rusty-pixel/theme.ron deleted file mode 100644 index 39e6af8..0000000 --- a/solitaire_engine/assets/themes/rusty-pixel/theme.ron +++ /dev/null @@ -1,76 +0,0 @@ -// Rusty Pixel — pixel-art card theme generated via Claude Design. -// -// 53 PNGs at 256×384 (4× nearest-neighbor upscale of the source -// 64×96 grid). Card aspect 2:3 matches the engine's layout -// assumption. Drop this directory under -// `/solitaire_quest/themes/rusty-pixel/` and the theme -// registry picks it up at next launch. -( - meta: ( - id: "rusty-pixel", - name: "Rusty Pixel", - author: "Claude Design", - version: "0.1.0", - card_aspect: (2, 3), - // Opt in to nearest-neighbor sampling so the pixel grid stays - // crisp at non-integer scales (Bevy's default bilinear filter - // mushes 256x384 pixel art when displayed at ~150x200 on a - // typical desktop window). - pixel_art: true, - ), - back: "back.png", - faces: { - "clubs_ace": "clubs_ace.png", - "clubs_2": "clubs_2.png", - "clubs_3": "clubs_3.png", - "clubs_4": "clubs_4.png", - "clubs_5": "clubs_5.png", - "clubs_6": "clubs_6.png", - "clubs_7": "clubs_7.png", - "clubs_8": "clubs_8.png", - "clubs_9": "clubs_9.png", - "clubs_10": "clubs_10.png", - "clubs_jack": "clubs_jack.png", - "clubs_queen": "clubs_queen.png", - "clubs_king": "clubs_king.png", - "diamonds_ace": "diamonds_ace.png", - "diamonds_2": "diamonds_2.png", - "diamonds_3": "diamonds_3.png", - "diamonds_4": "diamonds_4.png", - "diamonds_5": "diamonds_5.png", - "diamonds_6": "diamonds_6.png", - "diamonds_7": "diamonds_7.png", - "diamonds_8": "diamonds_8.png", - "diamonds_9": "diamonds_9.png", - "diamonds_10": "diamonds_10.png", - "diamonds_jack": "diamonds_jack.png", - "diamonds_queen": "diamonds_queen.png", - "diamonds_king": "diamonds_king.png", - "hearts_ace": "hearts_ace.png", - "hearts_2": "hearts_2.png", - "hearts_3": "hearts_3.png", - "hearts_4": "hearts_4.png", - "hearts_5": "hearts_5.png", - "hearts_6": "hearts_6.png", - "hearts_7": "hearts_7.png", - "hearts_8": "hearts_8.png", - "hearts_9": "hearts_9.png", - "hearts_10": "hearts_10.png", - "hearts_jack": "hearts_jack.png", - "hearts_queen": "hearts_queen.png", - "hearts_king": "hearts_king.png", - "spades_ace": "spades_ace.png", - "spades_2": "spades_2.png", - "spades_3": "spades_3.png", - "spades_4": "spades_4.png", - "spades_5": "spades_5.png", - "spades_6": "spades_6.png", - "spades_7": "spades_7.png", - "spades_8": "spades_8.png", - "spades_9": "spades_9.png", - "spades_10": "spades_10.png", - "spades_jack": "spades_jack.png", - "spades_queen": "spades_queen.png", - "spades_king": "spades_king.png", - }, -) diff --git a/solitaire_engine/src/assets/mod.rs b/solitaire_engine/src/assets/mod.rs index 99bb74e..e235edf 100644 --- a/solitaire_engine/src/assets/mod.rs +++ b/solitaire_engine/src/assets/mod.rs @@ -11,10 +11,8 @@ pub mod svg_loader; pub mod user_dir; pub use sources::{ - default_theme_svg_bytes, populate_embedded_default_theme, - populate_embedded_rusty_pixel_theme, register_theme_asset_sources, - rusty_pixel_theme_png_bytes, AssetSourcesPlugin, DEFAULT_THEME_MANIFEST_URL, - RUSTY_PIXEL_THEME_MANIFEST_URL, USER_THEMES, + default_theme_svg_bytes, populate_embedded_default_theme, register_theme_asset_sources, + AssetSourcesPlugin, DEFAULT_THEME_MANIFEST_URL, USER_THEMES, }; pub use svg_loader::{rasterize_svg, SvgLoader, SvgLoaderError, SvgLoaderSettings}; pub use user_dir::{set_user_theme_dir, user_theme_dir}; diff --git a/solitaire_engine/src/assets/sources.rs b/solitaire_engine/src/assets/sources.rs index c06d9ed..ab6275a 100644 --- a/solitaire_engine/src/assets/sources.rs +++ b/solitaire_engine/src/assets/sources.rs @@ -155,100 +155,6 @@ const DEFAULT_THEME_SVGS: &[(&str, &[u8])] = &[ embed_default_svg!("spades_king.svg"), ]; -/// Stable embedded asset URL of the bundled rusty-pixel theme manifest. -/// -/// `theme/plugin.rs::manifest_url_for` uses this when the player -/// selects "Rusty Pixel" so the manifest loads from the binary's -/// embedded asset registry rather than `themes://` (which would -/// require a user-supplied copy on disk). -pub const RUSTY_PIXEL_THEME_MANIFEST_URL: &str = - "embedded://solitaire_engine/assets/themes/rusty-pixel/theme.ron"; - -/// Path the embedded rusty-pixel theme manifest registers under, -/// relative to the `embedded://` source root. Kept in lockstep with -/// [`RUSTY_PIXEL_THEME_MANIFEST_URL`] by the unit test -/// `rusty_pixel_theme_url_constant_matches_embedded_path`. -const RUSTY_PIXEL_THEME_MANIFEST_PATH: &str = - "solitaire_engine/assets/themes/rusty-pixel/theme.ron"; - -/// Bytes of the bundled rusty-pixel theme manifest. Mirrors the -/// default-theme embed pattern — `include_bytes!` resolves at compile -/// time so the binary ships the manifest even on machines whose -/// `solitaire_engine/assets/` directory is absent at runtime. -const RUSTY_PIXEL_THEME_MANIFEST_BYTES: &[u8] = - include_bytes!("../../assets/themes/rusty-pixel/theme.ron"); - -/// Generates a `(stable_path, bytes)` entry for one rusty-pixel -/// theme PNG. Mirrors [`embed_default_svg!`] for the second bundled -/// theme — the path matches what `theme.ron` references. -macro_rules! embed_rusty_pixel_png { - ($name:literal) => { - ( - concat!("solitaire_engine/assets/themes/rusty-pixel/", $name), - include_bytes!(concat!("../../assets/themes/rusty-pixel/", $name)) as &[u8], - ) - }; -} - -/// Every rusty-pixel theme PNG bundled into the binary. 53 entries: -/// 52 face cards + 1 back. The macro pulls each PNG via -/// `include_bytes!` so adding a new file is a one-line append. -const RUSTY_PIXEL_THEME_PNGS: &[(&str, &[u8])] = &[ - embed_rusty_pixel_png!("back.png"), - embed_rusty_pixel_png!("clubs_ace.png"), - embed_rusty_pixel_png!("clubs_2.png"), - embed_rusty_pixel_png!("clubs_3.png"), - embed_rusty_pixel_png!("clubs_4.png"), - embed_rusty_pixel_png!("clubs_5.png"), - embed_rusty_pixel_png!("clubs_6.png"), - embed_rusty_pixel_png!("clubs_7.png"), - embed_rusty_pixel_png!("clubs_8.png"), - embed_rusty_pixel_png!("clubs_9.png"), - embed_rusty_pixel_png!("clubs_10.png"), - embed_rusty_pixel_png!("clubs_jack.png"), - embed_rusty_pixel_png!("clubs_queen.png"), - embed_rusty_pixel_png!("clubs_king.png"), - embed_rusty_pixel_png!("diamonds_ace.png"), - embed_rusty_pixel_png!("diamonds_2.png"), - embed_rusty_pixel_png!("diamonds_3.png"), - embed_rusty_pixel_png!("diamonds_4.png"), - embed_rusty_pixel_png!("diamonds_5.png"), - embed_rusty_pixel_png!("diamonds_6.png"), - embed_rusty_pixel_png!("diamonds_7.png"), - embed_rusty_pixel_png!("diamonds_8.png"), - embed_rusty_pixel_png!("diamonds_9.png"), - embed_rusty_pixel_png!("diamonds_10.png"), - embed_rusty_pixel_png!("diamonds_jack.png"), - embed_rusty_pixel_png!("diamonds_queen.png"), - embed_rusty_pixel_png!("diamonds_king.png"), - embed_rusty_pixel_png!("hearts_ace.png"), - embed_rusty_pixel_png!("hearts_2.png"), - embed_rusty_pixel_png!("hearts_3.png"), - embed_rusty_pixel_png!("hearts_4.png"), - embed_rusty_pixel_png!("hearts_5.png"), - embed_rusty_pixel_png!("hearts_6.png"), - embed_rusty_pixel_png!("hearts_7.png"), - embed_rusty_pixel_png!("hearts_8.png"), - embed_rusty_pixel_png!("hearts_9.png"), - embed_rusty_pixel_png!("hearts_10.png"), - embed_rusty_pixel_png!("hearts_jack.png"), - embed_rusty_pixel_png!("hearts_queen.png"), - embed_rusty_pixel_png!("hearts_king.png"), - embed_rusty_pixel_png!("spades_ace.png"), - embed_rusty_pixel_png!("spades_2.png"), - embed_rusty_pixel_png!("spades_3.png"), - embed_rusty_pixel_png!("spades_4.png"), - embed_rusty_pixel_png!("spades_5.png"), - embed_rusty_pixel_png!("spades_6.png"), - embed_rusty_pixel_png!("spades_7.png"), - embed_rusty_pixel_png!("spades_8.png"), - embed_rusty_pixel_png!("spades_9.png"), - embed_rusty_pixel_png!("spades_10.png"), - embed_rusty_pixel_png!("spades_jack.png"), - embed_rusty_pixel_png!("spades_queen.png"), - embed_rusty_pixel_png!("spades_king.png"), -]; - /// Registers asset sources that must be in place *before* /// `AssetPlugin` is built. /// @@ -285,7 +191,6 @@ pub struct AssetSourcesPlugin; impl Plugin for AssetSourcesPlugin { fn build(&self, app: &mut App) { populate_embedded_default_theme(app); - populate_embedded_rusty_pixel_theme(app); } } @@ -349,43 +254,6 @@ pub fn populate_embedded_default_theme(app: &mut App) { } } -/// Returns the embedded PNG bytes for a single rusty-pixel theme file -/// (e.g. `"back.png"` or `"spades_ace.png"`), or `None` when the -/// filename is not bundled. Mirrors [`default_theme_svg_bytes`] for -/// the second bundled theme so the picker thumbnail cache can read -/// preview-sized art without going through the async asset graph. -pub fn rusty_pixel_theme_png_bytes(filename: &str) -> Option<&'static [u8]> { - let suffix = format!("/{filename}"); - RUSTY_PIXEL_THEME_PNGS - .iter() - .find(|(path, _)| path.ends_with(&suffix)) - .map(|(_, bytes)| *bytes) -} - -/// Pushes the bundled rusty-pixel theme manifest + every face/back -/// PNG into the [`EmbeddedAssetRegistry`]. Pairs with -/// [`populate_embedded_default_theme`] — both are called from -/// [`AssetSourcesPlugin::build`] after `AssetPlugin` has set up the -/// embedded source. -pub fn populate_embedded_rusty_pixel_theme(app: &mut App) { - let registry = app - .world_mut() - .get_resource_or_insert_with(EmbeddedAssetRegistry::default); - - registry.insert_asset( - std::path::PathBuf::from(RUSTY_PIXEL_THEME_MANIFEST_PATH), - std::path::Path::new(RUSTY_PIXEL_THEME_MANIFEST_PATH), - RUSTY_PIXEL_THEME_MANIFEST_BYTES, - ); - for (path, bytes) in RUSTY_PIXEL_THEME_PNGS { - registry.insert_asset( - std::path::PathBuf::from(*path), - std::path::Path::new(*path), - *bytes, - ); - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/solitaire_engine/src/theme/plugin.rs b/solitaire_engine/src/theme/plugin.rs index 9292a4a..3e75ab6 100644 --- a/solitaire_engine/src/theme/plugin.rs +++ b/solitaire_engine/src/theme/plugin.rs @@ -17,8 +17,7 @@ use bevy::prelude::*; use solitaire_core::card::{Rank, Suit}; use crate::assets::{ - default_theme_svg_bytes, rasterize_svg, rusty_pixel_theme_png_bytes, user_theme_dir, - DEFAULT_THEME_MANIFEST_URL, RUSTY_PIXEL_THEME_MANIFEST_URL, + default_theme_svg_bytes, rasterize_svg, user_theme_dir, DEFAULT_THEME_MANIFEST_URL, }; use crate::card_plugin::CardImageSet; use crate::events::StateChangedEvent; @@ -129,32 +128,16 @@ fn load_initial_theme( settings: Option>, mut commands: Commands, ) { - let id = settings - .as_deref() - .map(|s| s.0.selected_theme_id.as_str()) - .unwrap_or("default"); - let url = manifest_url_for(id); + let url = match settings.as_deref() { + Some(s) if s.0.selected_theme_id != "default" => { + format!("themes://{}/theme.ron", s.0.selected_theme_id) + } + _ => DEFAULT_THEME_MANIFEST_URL.to_string(), + }; let handle: Handle = asset_server.load(url); commands.insert_resource(ActiveTheme(handle)); } -/// Resolves a theme id to its manifest asset URL. -/// -/// Bundled built-ins (default, rusty-pixel) route to `embedded://` -/// so the binary's compile-time-baked manifest + face files load -/// without touching disk. Anything else routes to `themes://`, -/// which `register_theme_asset_sources` points at the user themes -/// directory. Callers (load_initial_theme, -/// react_to_settings_theme_change) consult this helper instead of -/// hard-coding the URL shape per id. -fn manifest_url_for(theme_id: &str) -> String { - match theme_id { - "default" => DEFAULT_THEME_MANIFEST_URL.to_string(), - "rusty-pixel" => RUSTY_PIXEL_THEME_MANIFEST_URL.to_string(), - _ => format!("themes://{theme_id}/theme.ron"), - } -} - /// Watches [`crate::settings_plugin::SettingsChangedEvent`] and /// triggers a fresh theme load whenever /// `Settings::selected_theme_id` changes. The settings panel's theme @@ -180,7 +163,11 @@ fn react_to_settings_theme_change( return; } - let url = manifest_url_for(new_id); + let url = if new_id == "default" { + DEFAULT_THEME_MANIFEST_URL.to_string() + } else { + format!("themes://{new_id}/theme.ron") + }; let handle: Handle = asset_server.load(url); commands.insert_resource(ActiveTheme(handle)); } @@ -375,20 +362,11 @@ enum ThemePreviewBytes { /// `.svg` then `.png`. Either branch returns /// `None` on I/O failure (file missing, permission denied, etc.). fn read_theme_preview_bytes(theme_id: &str, basename: &str) -> Option { - // Bundled built-ins consult their embed tables before any - // filesystem I/O so the thumbnail works on a fresh install where - // the user themes directory doesn't exist yet. if theme_id == "default" { let filename = format!("{basename}.svg"); return default_theme_svg_bytes(&filename) .map(|b| ThemePreviewBytes::Svg(b.to_vec())); } - if theme_id == "rusty-pixel" { - let filename = format!("{basename}.png"); - if let Some(bytes) = rusty_pixel_theme_png_bytes(&filename) { - return Some(ThemePreviewBytes::Png(bytes.to_vec())); - } - } let dir = user_theme_dir().join(theme_id); if let Ok(bytes) = std::fs::read(dir.join(format!("{basename}.svg"))) { return Some(ThemePreviewBytes::Svg(bytes)); diff --git a/solitaire_engine/src/theme/registry.rs b/solitaire_engine/src/theme/registry.rs index e62bb28..6be6dad 100644 --- a/solitaire_engine/src/theme/registry.rs +++ b/solitaire_engine/src/theme/registry.rs @@ -25,7 +25,7 @@ use bevy::prelude::{App, Plugin, Resource, Startup}; use serde::Deserialize; use super::ThemeMeta; -use crate::assets::{user_theme_dir, DEFAULT_THEME_MANIFEST_URL, RUSTY_PIXEL_THEME_MANIFEST_URL}; +use crate::assets::{user_theme_dir, DEFAULT_THEME_MANIFEST_URL}; /// One entry in the [`ThemeRegistry`] — the data the picker UI needs /// to render a row and load the theme on selection. @@ -98,24 +98,10 @@ fn build_registry_on_startup(mut registry: bevy::ecs::system::ResMut ThemeRegistry { let mut entries = Vec::new(); entries.push(default_entry()); - entries.push(rusty_pixel_entry()); - let bundled_ids: std::collections::HashSet = - entries.iter().map(|e| e.id.clone()).collect(); - let user = discover_user_themes(user_dir) - .into_iter() - .filter(|t| !bundled_ids.contains(&t.id)); - entries.extend(user); + entries.extend(discover_user_themes(user_dir)); ThemeRegistry { entries } } @@ -137,26 +123,6 @@ fn default_entry() -> ThemeEntry { } } -/// The bundled rusty-pixel theme entry — pixel-art faces by Claude -/// Design, embedded under `embedded://solitaire_engine/assets/themes/rusty-pixel/`. -/// Inserted alongside the default so the picker offers both -/// out-of-the-box on a fresh install with no user themes directory. -fn rusty_pixel_entry() -> ThemeEntry { - ThemeEntry { - id: "rusty-pixel".to_string(), - display_name: "Rusty Pixel".to_string(), - manifest_url: RUSTY_PIXEL_THEME_MANIFEST_URL.to_string(), - meta: ThemeMeta { - id: "rusty-pixel".to_string(), - name: "Rusty Pixel".to_string(), - author: "Claude Design".to_string(), - version: "0.1.0".to_string(), - card_aspect: (2, 3), - pixel_art: true, - }, - } -} - /// Walks `user_dir`, treating every immediate subdirectory as a /// candidate theme. A subdirectory contributes one entry if and only /// if it contains a `theme.ron` whose `meta` block parses cleanly and @@ -274,22 +240,20 @@ mod tests { } #[test] - fn empty_user_dir_yields_only_the_bundled_built_ins() { + fn empty_user_dir_yields_only_the_default_entry() { let tmp = tempfile::tempdir().unwrap(); let registry = build_registry(tmp.path()); - assert_eq!(registry.len(), 2, "default + rusty-pixel always present"); + assert_eq!(registry.len(), 1); assert_eq!(registry.entries[0].id, "default"); - assert_eq!(registry.entries[1].id, "rusty-pixel"); } #[test] - fn nonexistent_user_dir_still_yields_bundled_built_ins() { + fn nonexistent_user_dir_still_yields_default() { let registry = build_registry(Path::new( "/definitely/not/a/real/path/should/not/panic", )); - assert_eq!(registry.len(), 2); + assert_eq!(registry.len(), 1); assert_eq!(registry.entries[0].id, "default"); - assert_eq!(registry.entries[1].id, "rusty-pixel"); } #[test] @@ -300,40 +264,12 @@ mod tests { write_manifest(&theme_dir, "midnight", "Midnight"); let registry = build_registry(tmp.path()); - assert_eq!(registry.len(), 3, "default + rusty-pixel + midnight"); + assert_eq!(registry.len(), 2); let entry = registry.find("midnight").expect("midnight registered"); assert_eq!(entry.display_name, "Midnight"); assert_eq!(entry.manifest_url, "themes://midnight/theme.ron"); } - #[test] - fn user_theme_id_collision_with_bundled_is_dropped() { - // A user-supplied directory whose `id` matches a bundled - // built-in (rusty-pixel) must not produce a duplicate - // registry entry. The bundled version wins because it's - // guaranteed complete; the user's overriding copy may be - // partial, stale, or otherwise broken. - let tmp = tempfile::tempdir().unwrap(); - let theme_dir = tmp.path().join("rusty-pixel"); - fs::create_dir_all(&theme_dir).unwrap(); - write_manifest(&theme_dir, "rusty-pixel", "User Override"); - - let registry = build_registry(tmp.path()); - assert_eq!( - registry.len(), 2, - "user override of bundled id must not appear as a duplicate", - ); - let entry = registry.find("rusty-pixel").expect("rusty-pixel registered"); - assert_eq!( - entry.display_name, "Rusty Pixel", - "bundled entry's display_name wins over the user override", - ); - assert_eq!( - entry.manifest_url, RUSTY_PIXEL_THEME_MANIFEST_URL, - "bundled embed:// URL wins over the user themes:// URL", - ); - } - #[test] fn full_manifest_also_works_via_meta_only_parser() { // The meta-only deserialiser must tolerate the full ThemeManifest @@ -374,9 +310,8 @@ mod tests { write_manifest(&theme_dir, "../etc/passwd", "Evil"); let registry = build_registry(tmp.path()); - assert_eq!(registry.len(), 2, "escape attempt must not register; built-ins remain"); + assert_eq!(registry.len(), 1, "escape attempt must not register"); assert_eq!(registry.entries[0].id, "default"); - assert_eq!(registry.entries[1].id, "rusty-pixel"); } #[test] @@ -387,11 +322,7 @@ mod tests { fs::write(lonely.join("readme.md"), "wrong filename").unwrap(); let registry = build_registry(tmp.path()); - assert_eq!( - registry.len(), - 2, - "no user themes register; only the bundled built-ins remain", - ); + assert_eq!(registry.len(), 1); } #[test] @@ -420,9 +351,8 @@ mod tests { refresh_registry(&mut registry, tmp.path()); - assert_eq!(registry.len(), 2, "stale entry replaced; built-ins remain"); + assert_eq!(registry.len(), 1); assert_eq!(registry.entries[0].id, "default"); - assert_eq!(registry.entries[1].id, "rusty-pixel"); assert!(registry.find("stale").is_none()); }