fix(engine): render bottom-right card glyph upright (no 180° rotation)

The user noticed the bottom-right large suit glyphs were
rendering upside-down — point-up hearts, stem-up spades — because
the SVG transform pipeline applied a `rotate(180)` to match the
traditional playing-card inverted-corner convention.

That convention exists so a card reads correctly when flipped or
read from the opposite side of the table. Single-orientation
digital play doesn't benefit from it; most modern digital decks
have abandoned it. User preference is upright.

Drops the rotate from face_svg's bottom-right `<g transform>`
and adjusts the translate so the visible glyph still lands at
(178, 286)–(242, 350) — same screen footprint, same scale, just
no flip.

design-system.md § Game Cards updated in lockstep — line 220
no longer says "rotated 180°", instead documents the deliberate
deviation from the traditional convention.

Knock-on lockstep changes in this commit:
- EXPECTED in tests/card_face_svg_pin.rs rebaselined: 52 face
  hashes shift, 5 back hashes unchanged.
- assets/cards/faces/*.png regenerated (52 face PNGs).
- solitaire_engine/assets/themes/default/*_*.svg regenerated
  (52 theme face SVGs that production rasterises at startup).

Workspace clippy + cargo test --workspace clean. Pin test
passes against the new hashes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
funman300
2026-05-08 10:09:55 -07:00
parent af414b6aed
commit dd101b3d54
107 changed files with 325 additions and 318 deletions
+12 -5
View File
@@ -220,6 +220,13 @@ pub fn face_svg(rank: Rank, suit: Suit) -> String {
// because the bundled `FiraMono` font doesn't carry usable
// U+2660-2666 glyphs at the requested size. See `suit_path_d`
// for the rationale.
//
// Both glyphs render in the same upright orientation. The
// traditional playing-card convention rotates the bottom-right
// indicator 180° so the card reads correctly when flipped, but
// most digital decks have abandoned that — single-orientation
// play doesn't benefit from the inverted-corner readback. See
// `design-system.md` § Game Cards for the spec deviation.
format!(
r##"<svg xmlns="http://www.w3.org/2000/svg" width="256" height="384" viewBox="0 0 256 384">
<rect x="1" y="1" width="254" height="382" rx="16" ry="16"
@@ -238,11 +245,11 @@ pub fn face_svg(rank: Rank, suit: Suit) -> String {
<path d="{path_d}" {small_glyph_attrs}/>
</g>
<!-- Bottom-right large suit glyph, 64 × 64, rotated 180° so it
reads upside-down (the convention for inverted-corner
indicators). The transform pipeline lands the glyph's visible
bottom-right at (242, 350) and visible top-left at (178, 286). -->
<g transform="translate(242 350) rotate(180) scale(2)">
<!-- Bottom-right large suit glyph at (178, 286), 64 × 64.
Visible bottom-right at (242, 350), visible top-left at
(178, 286). Same upright orientation as the top-left small
glyph — no 180° rotation applied. -->
<g transform="translate(178 286) scale(2)">
<path d="{path_d}" {large_glyph_attrs}/>
</g>
</svg>"##