diff --git a/assets/cards/backs/back_0.png b/assets/cards/backs/back_0.png index 28e92f1..fc207c3 100644 Binary files a/assets/cards/backs/back_0.png and b/assets/cards/backs/back_0.png differ diff --git a/assets/cards/backs/back_1.png b/assets/cards/backs/back_1.png index 8cc06c0..af8cc02 100644 Binary files a/assets/cards/backs/back_1.png and b/assets/cards/backs/back_1.png differ diff --git a/assets/cards/backs/back_2.png b/assets/cards/backs/back_2.png index 8346fa9..c432988 100644 Binary files a/assets/cards/backs/back_2.png and b/assets/cards/backs/back_2.png differ diff --git a/assets/cards/backs/back_3.png b/assets/cards/backs/back_3.png index ac070a0..1b2fbeb 100644 Binary files a/assets/cards/backs/back_3.png and b/assets/cards/backs/back_3.png differ diff --git a/assets/cards/backs/back_4.png b/assets/cards/backs/back_4.png index 9f16ff8..42b602e 100644 Binary files a/assets/cards/backs/back_4.png and b/assets/cards/backs/back_4.png differ diff --git a/assets/cards/faces/10C.png b/assets/cards/faces/10C.png index 0eec159..39f6953 100644 Binary files a/assets/cards/faces/10C.png and b/assets/cards/faces/10C.png differ diff --git a/assets/cards/faces/10D.png b/assets/cards/faces/10D.png index 20dcfa4..952f17d 100644 Binary files a/assets/cards/faces/10D.png and b/assets/cards/faces/10D.png differ diff --git a/assets/cards/faces/10H.png b/assets/cards/faces/10H.png index d60838b..8347275 100644 Binary files a/assets/cards/faces/10H.png and b/assets/cards/faces/10H.png differ diff --git a/assets/cards/faces/10S.png b/assets/cards/faces/10S.png index 24ec7c6..9c732dd 100644 Binary files a/assets/cards/faces/10S.png and b/assets/cards/faces/10S.png differ diff --git a/assets/cards/faces/2C.png b/assets/cards/faces/2C.png index 6899e79..8134924 100644 Binary files a/assets/cards/faces/2C.png and b/assets/cards/faces/2C.png differ diff --git a/assets/cards/faces/2D.png b/assets/cards/faces/2D.png index fed9bdc..155ab50 100644 Binary files a/assets/cards/faces/2D.png and b/assets/cards/faces/2D.png differ diff --git a/assets/cards/faces/2H.png b/assets/cards/faces/2H.png index fa94892..ebfa450 100644 Binary files a/assets/cards/faces/2H.png and b/assets/cards/faces/2H.png differ diff --git a/assets/cards/faces/2S.png b/assets/cards/faces/2S.png index a8a5894..0d5ee80 100644 Binary files a/assets/cards/faces/2S.png and b/assets/cards/faces/2S.png differ diff --git a/assets/cards/faces/3C.png b/assets/cards/faces/3C.png index 8857ae8..dfbfd87 100644 Binary files a/assets/cards/faces/3C.png and b/assets/cards/faces/3C.png differ diff --git a/assets/cards/faces/3D.png b/assets/cards/faces/3D.png index 64a1e12..9a6afa8 100644 Binary files a/assets/cards/faces/3D.png and b/assets/cards/faces/3D.png differ diff --git a/assets/cards/faces/3H.png b/assets/cards/faces/3H.png index 870fcf1..fb3a8bc 100644 Binary files a/assets/cards/faces/3H.png and b/assets/cards/faces/3H.png differ diff --git a/assets/cards/faces/3S.png b/assets/cards/faces/3S.png index 280dd88..87641cd 100644 Binary files a/assets/cards/faces/3S.png and b/assets/cards/faces/3S.png differ diff --git a/assets/cards/faces/4C.png b/assets/cards/faces/4C.png index 6c5bcb1..1d1801f 100644 Binary files a/assets/cards/faces/4C.png and b/assets/cards/faces/4C.png differ diff --git a/assets/cards/faces/4D.png b/assets/cards/faces/4D.png index 61a7522..e855c94 100644 Binary files a/assets/cards/faces/4D.png and b/assets/cards/faces/4D.png differ diff --git a/assets/cards/faces/4H.png b/assets/cards/faces/4H.png index f7d2240..30ee126 100644 Binary files a/assets/cards/faces/4H.png and b/assets/cards/faces/4H.png differ diff --git a/assets/cards/faces/4S.png b/assets/cards/faces/4S.png index 14b449a..8a9f6ca 100644 Binary files a/assets/cards/faces/4S.png and b/assets/cards/faces/4S.png differ diff --git a/assets/cards/faces/5C.png b/assets/cards/faces/5C.png index bd81b70..66de502 100644 Binary files a/assets/cards/faces/5C.png and b/assets/cards/faces/5C.png differ diff --git a/assets/cards/faces/5D.png b/assets/cards/faces/5D.png index 7f034ee..a6d7eec 100644 Binary files a/assets/cards/faces/5D.png and b/assets/cards/faces/5D.png differ diff --git a/assets/cards/faces/5H.png b/assets/cards/faces/5H.png index febddee..19ca087 100644 Binary files a/assets/cards/faces/5H.png and b/assets/cards/faces/5H.png differ diff --git a/assets/cards/faces/5S.png b/assets/cards/faces/5S.png index dd30b3e..0b83f51 100644 Binary files a/assets/cards/faces/5S.png and b/assets/cards/faces/5S.png differ diff --git a/assets/cards/faces/6C.png b/assets/cards/faces/6C.png index ac76ad0..bbdb6ac 100644 Binary files a/assets/cards/faces/6C.png and b/assets/cards/faces/6C.png differ diff --git a/assets/cards/faces/6D.png b/assets/cards/faces/6D.png index 44596bc..740ab42 100644 Binary files a/assets/cards/faces/6D.png and b/assets/cards/faces/6D.png differ diff --git a/assets/cards/faces/6H.png b/assets/cards/faces/6H.png index f34bcc7..07399f0 100644 Binary files a/assets/cards/faces/6H.png and b/assets/cards/faces/6H.png differ diff --git a/assets/cards/faces/6S.png b/assets/cards/faces/6S.png index 3fae288..7ffe917 100644 Binary files a/assets/cards/faces/6S.png and b/assets/cards/faces/6S.png differ diff --git a/assets/cards/faces/7C.png b/assets/cards/faces/7C.png index bcc188f..a5006f9 100644 Binary files a/assets/cards/faces/7C.png and b/assets/cards/faces/7C.png differ diff --git a/assets/cards/faces/7D.png b/assets/cards/faces/7D.png index 6a9726c..b77fe88 100644 Binary files a/assets/cards/faces/7D.png and b/assets/cards/faces/7D.png differ diff --git a/assets/cards/faces/7H.png b/assets/cards/faces/7H.png index 8eac5bc..9ee6ac9 100644 Binary files a/assets/cards/faces/7H.png and b/assets/cards/faces/7H.png differ diff --git a/assets/cards/faces/7S.png b/assets/cards/faces/7S.png index 3576b02..7bebe8a 100644 Binary files a/assets/cards/faces/7S.png and b/assets/cards/faces/7S.png differ diff --git a/assets/cards/faces/8C.png b/assets/cards/faces/8C.png index 826a1d3..9018ee4 100644 Binary files a/assets/cards/faces/8C.png and b/assets/cards/faces/8C.png differ diff --git a/assets/cards/faces/8D.png b/assets/cards/faces/8D.png index 282199d..b9d323c 100644 Binary files a/assets/cards/faces/8D.png and b/assets/cards/faces/8D.png differ diff --git a/assets/cards/faces/8H.png b/assets/cards/faces/8H.png index 00931af..4b4b596 100644 Binary files a/assets/cards/faces/8H.png and b/assets/cards/faces/8H.png differ diff --git a/assets/cards/faces/8S.png b/assets/cards/faces/8S.png index 5dc7719..36371e0 100644 Binary files a/assets/cards/faces/8S.png and b/assets/cards/faces/8S.png differ diff --git a/assets/cards/faces/9C.png b/assets/cards/faces/9C.png index 026e2b8..a98202d 100644 Binary files a/assets/cards/faces/9C.png and b/assets/cards/faces/9C.png differ diff --git a/assets/cards/faces/9D.png b/assets/cards/faces/9D.png index 58f35d2..8e9e3cc 100644 Binary files a/assets/cards/faces/9D.png and b/assets/cards/faces/9D.png differ diff --git a/assets/cards/faces/9H.png b/assets/cards/faces/9H.png index 0443dd9..03b790d 100644 Binary files a/assets/cards/faces/9H.png and b/assets/cards/faces/9H.png differ diff --git a/assets/cards/faces/9S.png b/assets/cards/faces/9S.png index aab5a88..b659087 100644 Binary files a/assets/cards/faces/9S.png and b/assets/cards/faces/9S.png differ diff --git a/assets/cards/faces/AC.png b/assets/cards/faces/AC.png index 5300624..4fb1eb3 100644 Binary files a/assets/cards/faces/AC.png and b/assets/cards/faces/AC.png differ diff --git a/assets/cards/faces/AD.png b/assets/cards/faces/AD.png index 8e5b0ea..d40fe47 100644 Binary files a/assets/cards/faces/AD.png and b/assets/cards/faces/AD.png differ diff --git a/assets/cards/faces/AH.png b/assets/cards/faces/AH.png index 635c3b3..af91dc6 100644 Binary files a/assets/cards/faces/AH.png and b/assets/cards/faces/AH.png differ diff --git a/assets/cards/faces/AS.png b/assets/cards/faces/AS.png index 9438649..2044a27 100644 Binary files a/assets/cards/faces/AS.png and b/assets/cards/faces/AS.png differ diff --git a/assets/cards/faces/JC.png b/assets/cards/faces/JC.png index 7684306..97fa126 100644 Binary files a/assets/cards/faces/JC.png and b/assets/cards/faces/JC.png differ diff --git a/assets/cards/faces/JD.png b/assets/cards/faces/JD.png index 9d58a97..112b719 100644 Binary files a/assets/cards/faces/JD.png and b/assets/cards/faces/JD.png differ diff --git a/assets/cards/faces/JH.png b/assets/cards/faces/JH.png index 796b6da..57f1dd2 100644 Binary files a/assets/cards/faces/JH.png and b/assets/cards/faces/JH.png differ diff --git a/assets/cards/faces/JS.png b/assets/cards/faces/JS.png index 72e7ca5..297ab8c 100644 Binary files a/assets/cards/faces/JS.png and b/assets/cards/faces/JS.png differ diff --git a/assets/cards/faces/KC.png b/assets/cards/faces/KC.png index b50eb29..98a3ef6 100644 Binary files a/assets/cards/faces/KC.png and b/assets/cards/faces/KC.png differ diff --git a/assets/cards/faces/KD.png b/assets/cards/faces/KD.png index 5878812..2898c30 100644 Binary files a/assets/cards/faces/KD.png and b/assets/cards/faces/KD.png differ diff --git a/assets/cards/faces/KH.png b/assets/cards/faces/KH.png index 94f5d6c..3d1076b 100644 Binary files a/assets/cards/faces/KH.png and b/assets/cards/faces/KH.png differ diff --git a/assets/cards/faces/KS.png b/assets/cards/faces/KS.png index 510bf07..eac2e72 100644 Binary files a/assets/cards/faces/KS.png and b/assets/cards/faces/KS.png differ diff --git a/assets/cards/faces/QC.png b/assets/cards/faces/QC.png index dd6cc6a..9c10284 100644 Binary files a/assets/cards/faces/QC.png and b/assets/cards/faces/QC.png differ diff --git a/assets/cards/faces/QD.png b/assets/cards/faces/QD.png index 1fc8c97..90ac3a7 100644 Binary files a/assets/cards/faces/QD.png and b/assets/cards/faces/QD.png differ diff --git a/assets/cards/faces/QH.png b/assets/cards/faces/QH.png index b99f466..9469d2c 100644 Binary files a/assets/cards/faces/QH.png and b/assets/cards/faces/QH.png differ diff --git a/assets/cards/faces/QS.png b/assets/cards/faces/QS.png index 55516f2..63e37cf 100644 Binary files a/assets/cards/faces/QS.png and b/assets/cards/faces/QS.png differ diff --git a/solitaire_engine/src/card_plugin.rs b/solitaire_engine/src/card_plugin.rs index 4a1bcd7..23e6908 100644 --- a/solitaire_engine/src/card_plugin.rs +++ b/solitaire_engine/src/card_plugin.rs @@ -61,9 +61,12 @@ pub const STACK_FAN_FRAC: f32 = 0.003; /// Font size as a fraction of card width. const FONT_SIZE_FRAC: f32 = 0.28; -pub const CARD_FACE_COLOUR: Color = Color::srgb(0.98, 0.98, 0.95); -pub const RED_SUIT_COLOUR: Color = Color::srgb(0.78, 0.12, 0.15); -pub const BLACK_SUIT_COLOUR: Color = Color::srgb(0.08, 0.08, 0.08); +/// Card-face background — Terminal `#1a1a1a` (BG_ELEVATED). +pub const CARD_FACE_COLOUR: Color = Color::srgb(0.102, 0.102, 0.102); +/// Suit colour for hearts + diamonds — Terminal `#fb9fb1` (suit-pink). +pub const RED_SUIT_COLOUR: Color = Color::srgb(0.984, 0.624, 0.694); +/// Suit colour for spades + clubs — Terminal `#d0d0d0` (TEXT_PRIMARY). +pub const BLACK_SUIT_COLOUR: Color = Color::srgb(0.816, 0.816, 0.816); /// Pre-loaded [`Handle`]s for card face and back PNG textures. /// @@ -94,19 +97,26 @@ pub struct CardImageSet { pub theme_back: Option>, } -/// Alternative face tint for red-suit cards in color-blind mode — a subtle -/// blue wash that distinguishes them from black-suit cards without colour alone. -const CARD_FACE_COLOUR_RED_CBM: Color = Color::srgba(0.85, 0.92, 1.0, 1.0); +/// Suit-colour swap for red-suit cards in colour-blind mode — Terminal +/// `#6fc2ef` (cyan). Replaces `RED_SUIT_COLOUR` (pink) when CBM is on, +/// providing a hue-distinct alternative that survives the most common +/// red/green deficiencies. Pre-Terminal this was a *face tint*; the new +/// design moves CBM differentiation into the suit glyph colour itself +/// and keeps the face uniformly `CARD_FACE_COLOUR` regardless of CBM. +const RED_SUIT_COLOUR_CBM: Color = Color::srgb(0.435, 0.761, 0.937); -/// Returns the card back color for the given unlocked card-back index. -/// Index 0 = default blue; 1–4 are unlockable alternate designs. +/// Returns the fallback card-back colour for the given unlocked card-back +/// index. Production renders backs from PNG artwork; this fallback only +/// fires under `MinimalPlugins` (tests). Mirrors the 5 accent colours +/// from `card_face_svg::BACK_ACCENTS` so the test-environment back lives +/// in the same hue family as the on-disk PNG art for that index. fn card_back_colour(selected_card_back: usize) -> Color { match selected_card_back { - 0 => Color::srgb(0.15, 0.30, 0.55), // default blue - 1 => Color::srgb(0.55, 0.10, 0.10), // deep red - 2 => Color::srgb(0.05, 0.40, 0.10), // forest green - 3 => Color::srgb(0.35, 0.08, 0.52), // purple - _ => Color::srgb(0.05, 0.40, 0.42), // teal (4+) + 0 => Color::srgb(0.435, 0.761, 0.937), // #6fc2ef cyan (Terminal canonical) + 1 => Color::srgb(0.675, 0.761, 0.404), // #acc267 lime + 2 => Color::srgb(0.882, 0.639, 0.933), // #e1a3ee lavender + 3 => Color::srgb(0.984, 0.624, 0.694), // #fb9fb1 pink + _ => Color::srgb(0.867, 0.698, 0.435), // #ddb26f gold (4+) } } @@ -400,7 +410,6 @@ fn card_sprite( card: &Card, card_size: Vec2, back_colour: Color, - color_blind: bool, card_images: Option<&CardImageSet>, selected_back: usize, ) -> Sprite { @@ -445,8 +454,13 @@ fn card_sprite( ..default() } } else { + // Terminal aesthetic: face background is uniformly CARD_FACE_COLOUR + // regardless of colour-blind mode (CBM differentiation now lives in + // the suit glyph colour, applied by `text_colour`, not the face + // background). Pre-Terminal this branch dispatched through a + // separate `face_colour(card, color_blind)` helper. let body_colour = if card.face_up { - face_colour(card, color_blind) + CARD_FACE_COLOUR } else { back_colour }; @@ -632,19 +646,6 @@ fn card_positions<'a>(game: &'a GameState, layout: &Layout) -> Vec<(&'a Card, Ve out } -/// Returns the appropriate face-up body colour for a card. -/// -/// In color-blind mode, red-suit cards receive a subtle blue tint -/// (`CARD_FACE_COLOUR_RED_CBM`) so they are distinguishable from black-suit -/// cards without relying on the text colour alone. -fn face_colour(card: &Card, color_blind: bool) -> Color { - if color_blind && card.suit.is_red() { - CARD_FACE_COLOUR_RED_CBM - } else { - CARD_FACE_COLOUR - } -} - #[allow(clippy::too_many_arguments)] fn spawn_card_entity( commands: &mut Commands, @@ -657,7 +658,7 @@ fn spawn_card_entity( card_images: Option<&CardImageSet>, selected_back: usize, ) { - let sprite = card_sprite(card, layout.card_size, back_colour, color_blind, card_images, selected_back); + let sprite = card_sprite(card, layout.card_size, back_colour, card_images, selected_back); let mut entity = commands.spawn(( CardEntity { card_id: card.id }, @@ -683,7 +684,7 @@ fn spawn_card_entity( font_size: layout.card_size.x * FONT_SIZE_FRAC, ..default() }, - TextColor(text_colour(card)), + TextColor(text_colour(card, color_blind)), Transform::from_xyz(0.0, 0.0, 0.01), label_visibility(card), )); @@ -710,7 +711,7 @@ fn update_card_entity( let target = Vec3::new(pos.x, pos.y, z); // Always refresh the visual appearance. - commands.entity(entity).insert(card_sprite(card, layout.card_size, back_colour, color_blind, card_images, selected_back)); + commands.entity(entity).insert(card_sprite(card, layout.card_size, back_colour, card_images, selected_back)); // Skip the snap/slide path entirely when a curve-based `CardAnimation` // is driving this card (e.g. the drag-rejection return tween). Writing @@ -755,7 +756,7 @@ fn update_card_entity( font_size: layout.card_size.x * FONT_SIZE_FRAC, ..default() }, - TextColor(text_colour(card)), + TextColor(text_colour(card, color_blind)), Transform::from_xyz(0.0, 0.0, 0.01), label_visibility(card), )); @@ -788,9 +789,21 @@ fn label_for(card: &Card) -> String { format!("{rank}{suit}") } -fn text_colour(card: &Card) -> Color { +/// Suit colour for the rank/suit overlay rendered atop the constant +/// fallback sprite (only fires under `MinimalPlugins` — production +/// renders the suit glyph baked into the PNG). When `color_blind` is +/// enabled, red-suit cards swap to `RED_SUIT_COLOUR_CBM` (cyan) — the +/// "Settings toggle swaps red→cyan" half of the design system's +/// colour-blind support. The other half (always-on filled-vs-outlined +/// glyph differentiation for ♥♠ vs ♦♣) is baked into the PNG art and +/// has no constant-fallback equivalent. +fn text_colour(card: &Card, color_blind: bool) -> Color { if card.suit.is_red() { - RED_SUIT_COLOUR + if color_blind { + RED_SUIT_COLOUR_CBM + } else { + RED_SUIT_COLOUR + } } else { BLACK_SUIT_COLOUR } @@ -1746,8 +1759,8 @@ mod tests { rank: Rank::Ace, face_up: true, }; - assert_eq!(text_colour(&h), RED_SUIT_COLOUR); - assert_eq!(text_colour(&d), RED_SUIT_COLOUR); + assert_eq!(text_colour(&h, false), RED_SUIT_COLOUR); + assert_eq!(text_colour(&d, false), RED_SUIT_COLOUR); } #[test] @@ -1764,8 +1777,8 @@ mod tests { rank: Rank::Ace, face_up: true, }; - assert_eq!(text_colour(&c), BLACK_SUIT_COLOUR); - assert_eq!(text_colour(&s), BLACK_SUIT_COLOUR); + assert_eq!(text_colour(&c, false), BLACK_SUIT_COLOUR); + assert_eq!(text_colour(&s, false), BLACK_SUIT_COLOUR); } #[test] @@ -2048,38 +2061,35 @@ mod tests { } // ----------------------------------------------------------------------- - // face_colour (pure) — color-blind mode + // text_colour (pure) — color-blind mode + // + // Pre-Terminal these were `face_colour` tests asserting that CBM + // tinted the *face background* of red-suit cards. The Terminal + // design system moves CBM differentiation into the suit *glyph* + // colour (red→cyan), so these tests now exercise `text_colour`. // ----------------------------------------------------------------------- #[test] - fn face_colour_normal_mode_returns_card_face_colour_for_red_suit() { - let card = Card { id: 0, suit: Suit::Hearts, rank: Rank::King, face_up: true }; - assert_eq!(face_colour(&card, false), CARD_FACE_COLOUR); - } - - #[test] - fn face_colour_normal_mode_returns_card_face_colour_for_black_suit() { - let card = Card { id: 0, suit: Suit::Spades, rank: Rank::King, face_up: true }; - assert_eq!(face_colour(&card, false), CARD_FACE_COLOUR); - } - - #[test] - fn face_colour_color_blind_mode_gives_red_suits_a_different_tint() { + fn text_colour_color_blind_mode_swaps_red_suits_to_cyan() { let red_card = Card { id: 0, suit: Suit::Diamonds, rank: Rank::Queen, face_up: true }; - let cbm_colour = face_colour(&red_card, true); + let cbm_colour = text_colour(&red_card, true); + assert_eq!( + cbm_colour, RED_SUIT_COLOUR_CBM, + "color-blind mode must replace the red suit colour with the CBM cyan", + ); assert_ne!( - cbm_colour, CARD_FACE_COLOUR, - "color-blind mode must tint red-suit cards differently from the standard face colour" + cbm_colour, RED_SUIT_COLOUR, + "CBM red must be visibly distinct from the default red suit colour", ); } #[test] - fn face_colour_color_blind_mode_does_not_change_black_suits() { + fn text_colour_color_blind_mode_does_not_change_black_suits() { let black_card = Card { id: 0, suit: Suit::Clubs, rank: Rank::Jack, face_up: true }; assert_eq!( - face_colour(&black_card, true), - CARD_FACE_COLOUR, - "color-blind mode must not alter black-suit card face colour" + text_colour(&black_card, true), + BLACK_SUIT_COLOUR, + "color-blind mode must not alter black-suit text colour", ); } @@ -2633,7 +2643,6 @@ mod tests { &face_down, Vec2::new(80.0, 112.0), card_back_colour(2), - false, Some(&set), 2, ); @@ -2666,7 +2675,6 @@ mod tests { &face_down, Vec2::new(80.0, 112.0), card_back_colour(selected_back), - false, Some(&set), selected_back, );