feat(assets): swap card art to hayeah/playing-cards-assets (MIT)

Replaces the previous xCards-derived card faces (LGPL-3.0) with
hayeah/playing-cards-assets, which itself derives from the
public-domain vector-playing-cards Google Code project. The whole
package is MIT now — see CREDITS.md for the new attribution table
and the simpler license summary.

solitaire_engine/assets/themes/default/
  52 face SVGs (clubs/diamonds/hearts/spades × ace/2-10/jack/queen/
  king) — copied from hayeah, renamed to the canonical
  `{suit}_{rank}.svg` form `CardKey::manifest_name` produces. The
  bundled default theme manifest references each by the same name.
  back.svg — original midnight-purple-themed card back, hand-written
  to match the project's design tokens (BG_BASE / BG_ELEVATED /
  ACCENT_PRIMARY / ACCENT_SECONDARY). MIT, original work.

assets/cards/faces/{RANK}{SUIT}.png
  52 PNGs regenerated from the new SVGs at 750-tall via resvg 0.47.
  These remain the legacy backwards-compat path that
  `card_plugin::load_card_images` reads at startup; once the runtime
  theme system finishes loading the embedded default theme, the
  CardImageSet's face handles are overwritten with the SVG-rendered
  variants and these PNGs become moot. Keeping them in place avoids
  a brief blank-card flash before the async theme load completes.

solitaire_engine/src/assets/sources.rs
  embed_default_svg!() macro + DEFAULT_THEME_SVGS table that bundles
  every face + the back into the binary at compile time via
  include_bytes!. populate_embedded_default_theme now iterates the
  table so the EmbeddedAssetRegistry is populated under the same
  asset paths the manifest references.

CREDITS.md
  License summary collapses from MIT + LGPL-3.0 + OFL-1.1 to MIT +
  OFL-1.1 (the OFL still applies to FiraMono). The hayeah upstream
  URL replaces the previously-blank xCards entry.

cargo build / clippy --workspace --all-targets -- -D warnings / test
--workspace all green (960 passed, 0 failed, 9 ignored).
This commit is contained in:
funman300
2026-05-01 16:06:58 +00:00
parent 7b59e70192
commit b98cb8a99f
107 changed files with 14996 additions and 22 deletions
+95 -10
View File
@@ -83,6 +83,78 @@ const DEFAULT_THEME_MANIFEST_PATH: &str = "solitaire_engine/assets/themes/defaul
const DEFAULT_THEME_MANIFEST_BYTES: &[u8] =
include_bytes!("../../assets/themes/default/theme.ron");
/// Generates a `(stable_path, bytes)` entry for one default-theme
/// SVG so the bulk-embed table below stays declarative. The path
/// matches what `theme.ron` references; `include_bytes!` resolves
/// relative to this source file.
macro_rules! embed_default_svg {
($name:literal) => {
(
concat!("solitaire_engine/assets/themes/default/", $name),
include_bytes!(concat!("../../assets/themes/default/", $name)) as &[u8],
)
};
}
/// Every default-theme SVG file bundled into the binary. Adding a new
/// face / back artwork is a single `embed_default_svg!(...)` line —
/// the populate function below iterates this table.
const DEFAULT_THEME_SVGS: &[(&str, &[u8])] = &[
embed_default_svg!("back.svg"),
embed_default_svg!("clubs_ace.svg"),
embed_default_svg!("clubs_2.svg"),
embed_default_svg!("clubs_3.svg"),
embed_default_svg!("clubs_4.svg"),
embed_default_svg!("clubs_5.svg"),
embed_default_svg!("clubs_6.svg"),
embed_default_svg!("clubs_7.svg"),
embed_default_svg!("clubs_8.svg"),
embed_default_svg!("clubs_9.svg"),
embed_default_svg!("clubs_10.svg"),
embed_default_svg!("clubs_jack.svg"),
embed_default_svg!("clubs_queen.svg"),
embed_default_svg!("clubs_king.svg"),
embed_default_svg!("diamonds_ace.svg"),
embed_default_svg!("diamonds_2.svg"),
embed_default_svg!("diamonds_3.svg"),
embed_default_svg!("diamonds_4.svg"),
embed_default_svg!("diamonds_5.svg"),
embed_default_svg!("diamonds_6.svg"),
embed_default_svg!("diamonds_7.svg"),
embed_default_svg!("diamonds_8.svg"),
embed_default_svg!("diamonds_9.svg"),
embed_default_svg!("diamonds_10.svg"),
embed_default_svg!("diamonds_jack.svg"),
embed_default_svg!("diamonds_queen.svg"),
embed_default_svg!("diamonds_king.svg"),
embed_default_svg!("hearts_ace.svg"),
embed_default_svg!("hearts_2.svg"),
embed_default_svg!("hearts_3.svg"),
embed_default_svg!("hearts_4.svg"),
embed_default_svg!("hearts_5.svg"),
embed_default_svg!("hearts_6.svg"),
embed_default_svg!("hearts_7.svg"),
embed_default_svg!("hearts_8.svg"),
embed_default_svg!("hearts_9.svg"),
embed_default_svg!("hearts_10.svg"),
embed_default_svg!("hearts_jack.svg"),
embed_default_svg!("hearts_queen.svg"),
embed_default_svg!("hearts_king.svg"),
embed_default_svg!("spades_ace.svg"),
embed_default_svg!("spades_2.svg"),
embed_default_svg!("spades_3.svg"),
embed_default_svg!("spades_4.svg"),
embed_default_svg!("spades_5.svg"),
embed_default_svg!("spades_6.svg"),
embed_default_svg!("spades_7.svg"),
embed_default_svg!("spades_8.svg"),
embed_default_svg!("spades_9.svg"),
embed_default_svg!("spades_10.svg"),
embed_default_svg!("spades_jack.svg"),
embed_default_svg!("spades_queen.svg"),
embed_default_svg!("spades_king.svg"),
];
/// Registers asset sources that must be in place *before*
/// `AssetPlugin` is built.
///
@@ -128,26 +200,39 @@ impl Plugin for AssetSourcesPlugin {
/// unit test below can exercise it without spinning up a full Bevy
/// `App` with `AssetPlugin`.
///
/// **Adding files to the bundled default theme** is a single edit
/// per file: add an `include_bytes!` constant that points at the file
/// under `solitaire_engine/assets/themes/default/`, then add a
/// matching `registry.insert_asset(...)` call here. Keep the
/// `asset_path` argument exactly the relative path that the manifest
/// references (e.g. `solitaire_engine/assets/themes/default/back.svg`).
/// **Adding files to the bundled default theme** is a single edit:
/// append one `embed_default_svg!("filename.svg")` line to the
/// `DEFAULT_THEME_SVGS` table above. The file resolves relative to
/// `solitaire_engine/assets/themes/default/` and registers under
/// the matching `embedded://` URL automatically.
pub fn populate_embedded_default_theme(app: &mut App) {
let registry = app
.world_mut()
.get_resource_or_insert_with(EmbeddedAssetRegistry::default);
// `full_path` is only consulted by the optional
// `embedded_watcher` cargo feature (which we don't enable). Use
// the manifest's logical workspace path so a future debugger
// session sees a sensible source-of-truth string.
// The manifest first — its asset URL is the entry point everything
// else (`set_theme`, the registry, the loader) references via
// `DEFAULT_THEME_MANIFEST_URL`.
//
// `full_path` is only consulted by the optional `embedded_watcher`
// cargo feature (which we don't enable). Use the manifest's
// logical workspace path so a future debugger session sees a
// sensible source-of-truth string.
registry.insert_asset(
std::path::PathBuf::from(DEFAULT_THEME_MANIFEST_PATH),
std::path::Path::new(DEFAULT_THEME_MANIFEST_PATH),
DEFAULT_THEME_MANIFEST_BYTES,
);
// Then every face + back SVG. The manifest references each by the
// same relative path used here.
for (path, bytes) in DEFAULT_THEME_SVGS {
registry.insert_asset(
std::path::PathBuf::from(*path),
std::path::Path::new(*path),
*bytes,
);
}
}
#[cfg(test)]