From 2186f559131bb762d7840c83c89f8db7d880ac3f Mon Sep 17 00:00:00 2001 From: funman300 Date: Tue, 19 May 2026 14:34:04 -0700 Subject: [PATCH] fix(engine): fix classic-card corner label colours and HUD-band overlap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit card_plugin: AndroidCornerLabel used CARD_FACE_COLOUR (dark ~#1a1a1a) as the background and BLACK_SUIT_COLOUR (near-white) for clubs/spades text — both designed for the Terminal theme. On classic PNG cards (white face), this produced an ugly dark box with invisible black-suit text. Switch the corner-label background to Color::WHITE and black-suit text to CARD_FACE_COLOUR (dark ink on white), matching traditional card printing. layout: HUD_BAND_HEIGHT on Android raised 80 → 112 px. The HUD column has 4 flex tiers plus 3 inter-tier gaps (4 px each) and a SPACE_2 = 8 px top offset. With empty tiers still occupying gap height in Bevy's flex layout, the actual rendered HUD could reach ~80 px, overlapping the top card row by up to one text line. 112 px provides ~28 px clearance in the common case (Tiers 1 + 3 visible) and remains workable even when Tier 1 wraps. Co-Authored-By: Claude Sonnet 4.6 --- CLAUDE.md | 2 +- solitaire_engine/src/card_plugin.rs | 24 +++++++++++++++++++++--- solitaire_engine/src/layout.rs | 11 +++++++---- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index ceba491..c59ede5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -355,7 +355,7 @@ Must always be handled explicitly: * The gesture/navigation bar at the bottom (≈132px physical on common devices) is inside the Bevy viewport; use `SafeAreaInsets.bottom` to avoid placing interactive elements in that zone -* `HUD_BAND_HEIGHT` is 128px on Android (two-row wrap) vs 64px on desktop; +* `HUD_BAND_HEIGHT` is 112px on Android vs 64px on desktop; layout constants are `#[cfg(target_os = "android")]` gated * JNI calls must use `attach_current_thread_permanently` — not `attach_current_thread` — to avoid detach-on-drop panics diff --git a/solitaire_engine/src/card_plugin.rs b/solitaire_engine/src/card_plugin.rs index 8eb5a74..e316f3b 100644 --- a/solitaire_engine/src/card_plugin.rs +++ b/solitaire_engine/src/card_plugin.rs @@ -1147,11 +1147,13 @@ fn add_android_corner_label( let bg_w = font_size * 2.0; let bg_h = font_size * 1.25; - // Solid background that hides the card art's small corner label. + // Background covers the PNG's baked-in small corner text. + // Classic PNG cards have a white face, so the background must be white too. + // (CARD_FACE_COLOUR is the Terminal theme's dark face colour — wrong here.) parent.spawn(( AndroidCornerBg, Sprite { - color: CARD_FACE_COLOUR, + color: Color::WHITE, custom_size: Some(Vec2::new(bg_w, bg_h)), ..default() }, @@ -1165,6 +1167,22 @@ fn add_android_corner_label( // Large rank+suit text drawn on top of the background. FiraMono must be // wired here explicitly — the suit glyphs (U+2660–U+2666) are not in // Bevy's built-in font and render as a coloured rectangle without it. + // + // Classic PNG cards have a white face: red suits stay the same saturated + // red, but black suits must use a dark colour (CARD_FACE_COLOUR ≈ #1a1a1a) + // rather than the near-white BLACK_SUIT_COLOUR designed for the dark + // Terminal theme background. + let text_col = if card.suit.is_red() { + if color_blind { + RED_SUIT_COLOUR_CBM + } else if high_contrast { + RED_SUIT_COLOUR_HC + } else { + RED_SUIT_COLOUR + } + } else { + CARD_FACE_COLOUR + }; let label_text = mobile_label_for(card); parent.spawn(( AndroidCornerLabel(label_text.clone()), @@ -1175,7 +1193,7 @@ fn add_android_corner_label( font_size, ..default() }, - TextColor(text_colour(card, color_blind, high_contrast)), + TextColor(text_col), Anchor::TOP_LEFT, Transform::from_xyz( -card_size.x / 2.0 + inset, diff --git a/solitaire_engine/src/layout.rs b/solitaire_engine/src/layout.rs index 624c8c0..1c7fa0a 100644 --- a/solitaire_engine/src/layout.rs +++ b/solitaire_engine/src/layout.rs @@ -96,13 +96,16 @@ const MAX_TABLEAU_CARDS: f32 = 13.0; /// below this band so the HUD doesn't bleed into the play surface. /// /// Desktop: 64 px fits the score/moves/time + mode badge rows. -/// Android: 80 px gives the same content rows comfortable clearance. -/// (Previously 128 px when action buttons lived in the top band; those are -/// now in the bottom bar so the larger reserve is no longer needed.) +/// Android: 112 px — the HUD column has 4 flex tiers with 3 inter-tier +/// gaps (4 px each) plus a SPACE_2 = 8 px top offset. With empty tiers +/// still contributing gap height in Bevy's flex layout, the actual HUD +/// height can reach ~80 px before the grid starts; 112 px gives ~28 px +/// of clearance between the HUD bottom and the top card edge, preventing +/// the overlap seen with the previous 80 px value. #[cfg(not(target_os = "android"))] pub const HUD_BAND_HEIGHT: f32 = 64.0; #[cfg(target_os = "android")] -pub const HUD_BAND_HEIGHT: f32 = 80.0; +pub const HUD_BAND_HEIGHT: f32 = 112.0; /// Table background colour (dark green felt). pub const TABLE_COLOUR: [f32; 3] = [0.059, 0.322, 0.196];