From fdb6c2ecfe17654d90d891e4153f8e825fead9bc Mon Sep 17 00:00:00 2001 From: funman300 Date: Fri, 1 May 2026 21:41:35 +0000 Subject: [PATCH] fix(engine): bundle FiraMono into SVG fontdb as last-resort fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hayeah card SVGs reference Bitstream Vera Sans and Arial by name. The lenient FontResolver from efa063f appends Family::SansSerif and Family::Serif so unmatched named families fall through to whatever the system serves under those CSS generics — which works on machines with a normal fontconfig setup, and silently fails on minimal Linux installs, fresh Wayland sessions, or chroots where the generic aliases don't resolve to anything either. The visible symptom on the player's second machine was "card font didn't carry over": rank and suit glyphs vanished from the cards because every lookup path hit a None. shared_fontdb now also include_bytes!()s the bundled assets/fonts/main.ttf into the fontdb after load_system_fonts, and pins each CSS generic (sans-serif, serif, monospace, cursive, fantasy) to "Fira Mono". Named-family lookups still prefer the system db first when those families exist, so machines with a normal font setup behave identically; only when SansSerif/Serif fall through does the resolver land on FiraMono — guaranteed present because it's embedded in the binary. The bundled font is ~170 KB; the binary already include_bytes!()s the six audio WAVs and the embedded card-theme SVGs, so this fits the existing self-contained-binary policy. Co-Authored-By: Claude Opus 4.7 (1M context) --- solitaire_engine/src/assets/svg_loader.rs | 43 +++++++++++++++++++---- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/solitaire_engine/src/assets/svg_loader.rs b/solitaire_engine/src/assets/svg_loader.rs index fa1ed7e..97c7db0 100644 --- a/solitaire_engine/src/assets/svg_loader.rs +++ b/solitaire_engine/src/assets/svg_loader.rs @@ -153,13 +153,28 @@ pub fn rasterize_svg(svg_bytes: &[u8], target: UVec2) -> Result Arc { DB.get_or_init(|| { let mut db = fontdb::Database::new(); db.load_system_fonts(); + // The bundled FiraMono lives at the workspace root, so the + // include_bytes! path goes up three levels from this source + // file (assets → src → solitaire_engine → workspace root). + db.load_font_data(include_bytes!("../../../assets/fonts/main.ttf").to_vec()); + // Pin the CSS generics to the bundled face as the resolution + // target. Named-family lookups (Bitstream Vera Sans, Arial) + // still try the system db first; only when those miss does + // the resolver fall through to SansSerif / Serif, and now + // those are guaranteed to land on FiraMono. + db.set_sans_serif_family("Fira Mono"); + db.set_serif_family("Fira Mono"); + db.set_monospace_family("Fira Mono"); + db.set_cursive_family("Fira Mono"); + db.set_fantasy_family("Fira Mono"); Arc::new(db) }) .clone()