From 3388169329d510e4c1b0953d1e71fc4986538604 Mon Sep 17 00:00:00 2001 From: funman300 Date: Mon, 13 Jul 2026 16:52:16 -0700 Subject: [PATCH] fix(engine): platform-correct onboarding copy; Home waits for first-run onboarding (Phase H) - The how-to-play slide told touch players to left/right-click; Android now gets tap/double-tap copy pointing at the bottom-bar Hint button. - On a fresh profile the Home auto-show spawned underneath the onboarding modal, stacking two scrims (v0.44.0 emulator smoke finding). spawn_home_on_launch now waits until first_run_complete and the onboarding modal is gone, so the launch beat is onboarding, then Home, then the table. Co-Authored-By: Claude Fable 5 --- solitaire_engine/src/animation_plugin.rs | 2 +- solitaire_engine/src/home_plugin.rs | 11 +++++++++ solitaire_engine/src/onboarding_plugin.rs | 27 ++++++++++++++--------- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/solitaire_engine/src/animation_plugin.rs b/solitaire_engine/src/animation_plugin.rs index 50801f5..b71c432 100644 --- a/solitaire_engine/src/animation_plugin.rs +++ b/solitaire_engine/src/animation_plugin.rs @@ -29,8 +29,8 @@ use crate::events::{ use crate::game_plugin::GameMutation; use crate::layout::LayoutResource; use crate::pause_plugin::PausedResource; -use crate::progress_plugin::LevelUpEvent; use crate::platform::USE_TOUCH_UI_LAYOUT; +use crate::progress_plugin::LevelUpEvent; use crate::safe_area::SafeAreaAnchoredBottom; use crate::settings_plugin::{SettingsChangedEvent, SettingsResource}; use crate::time_attack_plugin::TimeAttackEndedEvent; diff --git a/solitaire_engine/src/home_plugin.rs b/solitaire_engine/src/home_plugin.rs index 721c31f..1ca0323 100644 --- a/solitaire_engine/src/home_plugin.rs +++ b/solitaire_engine/src/home_plugin.rs @@ -475,6 +475,11 @@ fn persist_last_mode( /// must be empty — when the player has a saved in-progress game the /// restore prompt takes precedence; the home picker would compete /// with it for attention. +/// * First-run onboarding must be finished (`Settings.first_run_complete` +/// and no `OnboardingScreen` open) — on a fresh profile the onboarding +/// owns the launch beat; Home appearing underneath it stacked two +/// modals (Phase H fix; spotted in the v0.44.0 emulator smoke). Home +/// spawns on the first frame after the player finishes or skips. /// * `HomeScreen` must not already exist (defensive — e.g. the player /// pressed `M` between ticks). /// * `LaunchHomeShown` flips to `true` after the first spawn so this @@ -488,6 +493,7 @@ fn spawn_home_on_launch( splash: Query<(), With>, restore_prompts: Query<(), With>, pending_restore: Option>, + onboarding: Query<(), With>, existing: Query<(), With>, sources: HomeSpawnSources, mut deal_expanded: ResMut, @@ -496,6 +502,11 @@ fn spawn_home_on_launch( || !splash.is_empty() || !restore_prompts.is_empty() || pending_restore.as_ref().is_some_and(|p| p.0.is_some()) + || !onboarding.is_empty() + || sources + .settings + .as_ref() + .is_some_and(|s| !s.0.first_run_complete) || !existing.is_empty() { return; diff --git a/solitaire_engine/src/onboarding_plugin.rs b/solitaire_engine/src/onboarding_plugin.rs index bd26030..8c42655 100644 --- a/solitaire_engine/src/onboarding_plugin.rs +++ b/solitaire_engine/src/onboarding_plugin.rs @@ -382,20 +382,27 @@ fn spawn_slide_welcome(commands: &mut Commands, font_res: Option<&FontResource>) }); } +/// How-to-play body copy, phrased for the platform's input vocabulary — +/// a touch player never left-clicks (Phase H polish; spotted in the +/// emulator smoke of v0.44.0). +#[cfg(target_os = "android")] +const HOW_TO_PLAY_BODY: &str = "Drag any face-up card to move it between piles. \ + You can drag a whole column at once by grabbing the topmost card \ + you want to move. Double-tap a face-up card to send it to a \ + foundation pile automatically (when the move is legal). \ + Tap Hint in the bottom bar for a suggested move."; +#[cfg(not(target_os = "android"))] +const HOW_TO_PLAY_BODY: &str = "Left-click and drag any face-up card to move it between piles. \ + You can drag a whole column at once by grabbing the topmost card \ + you want to move. Double-click a face-up card to send it to a \ + foundation pile automatically (when the move is legal). \ + Right-click a card for a hint — valid destinations will highlight."; + /// Slide 2 — How to play. fn spawn_slide_how_to_play(commands: &mut Commands, font_res: Option<&FontResource>) { spawn_modal(commands, OnboardingScreen, Z_ONBOARDING, |card| { spawn_modal_header(card, "Drag cards to play", font_res); - spawn_modal_body_text( - card, - "Left-click and drag any face-up card to move it between piles. \ - You can drag a whole column at once by grabbing the topmost card \ - you want to move. Double-click a face-up card to send it to a \ - foundation pile automatically (when the move is legal). \ - Right-click a card for a hint — valid destinations will highlight.", - TEXT_SECONDARY, - font_res, - ); + spawn_modal_body_text(card, HOW_TO_PLAY_BODY, TEXT_SECONDARY, font_res); spawn_modal_actions(card, |actions| { spawn_modal_button( actions,