Files
Ferrous-Solitaire/solitaire_engine/src/lib.rs
T
funman300 36605751cd
Test / fmt (pull_request) Successful in 4s
Test / test (pull_request) Successful in 4m33s
feat(engine): hold-/ hotkey cheat sheet + unified binding table (Phase J)
Phase J audit findings: the visible focus ring the doc asked for
already exists (FocusOverlay singleton, 2px accent ring, breathing
pulse, reduce-motion aware — landed after the doc was written), and
post-Phase-C every modal already opens and dismisses keyboard-only.
The real gaps were two silently diverging static hotkey tables
(onboarding's slide vs Help's list — onboarding still said 'Mode
Launcher (then 1-5)') and no way to see the bindings mid-game.

- New crate::hotkeys module owns THE binding table (21 rows, verified
  against a grep inventory of every just_pressed(KeyCode::..) handler);
  rows carry an `essential` flag — the onboarding slide teaches that
  subset, the cheat sheet shows everything.
- New cheat_sheet_plugin: hold `/` for a right-anchored reference
  overlay of every binding; release hides it. Deliberately not a
  spawn_modal modal (momentary reference, closer to a tooltip), never
  spawns while a modal owns the screen (also keeps it out of the
  seed-entry field), inert on touch builds.
- Onboarding's stale local table deleted in favour of the shared one
  (copy updated: Home naming, hold-to-repeat undo, added H).

5 new tests (table integrity, essential-subset size, uniqueness,
show/hide driver, modal suppression). Workspace + clippy green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 18:58:23 -07:00

208 lines
8.5 KiB
Rust

//! Bevy integration layer for Ferrous Solitaire.
pub mod achievement_plugin;
#[cfg(not(target_arch = "wasm32"))]
pub mod analytics_plugin;
#[cfg(target_os = "android")]
pub mod android_clipboard;
pub mod animation_plugin;
pub mod assets;
#[cfg(not(target_arch = "wasm32"))]
pub mod audio_plugin;
pub mod auto_complete_plugin;
#[cfg(not(target_arch = "wasm32"))]
pub mod avatar_plugin;
pub mod card_animation;
pub mod card_plugin;
pub mod challenge_plugin;
pub mod cheat_sheet_plugin;
pub mod contextual_tips_plugin;
pub mod core_game_plugin;
pub mod cursor_plugin;
pub mod daily_challenge_plugin;
pub mod diagnostics_hud;
pub mod difficulty_plugin;
pub mod events;
pub mod feedback_anim_plugin;
pub mod font_plugin;
pub mod game_plugin;
pub mod help_plugin;
pub mod home_plugin;
pub mod hotkeys;
pub mod hud_plugin;
pub mod input_plugin;
pub mod layout;
#[cfg(not(target_arch = "wasm32"))]
pub mod leaderboard_plugin;
pub mod onboarding_plugin;
pub mod pause_plugin;
pub mod pending_hint;
pub mod platform;
pub mod play_by_seed_plugin;
pub mod profile_plugin;
pub mod progress_plugin;
pub mod radial_menu;
pub mod replay_overlay;
pub mod replay_playback;
pub mod resources;
pub mod safe_area;
mod schedule_checks;
pub mod selection_plugin;
pub mod settings_plugin;
pub mod solution_playback_plugin;
pub mod splash_plugin;
pub mod stats_plugin;
#[cfg(not(target_arch = "wasm32"))]
pub mod sync_plugin;
#[cfg(not(target_arch = "wasm32"))]
pub mod sync_setup_plugin;
pub mod table_plugin;
pub mod theme;
#[cfg(not(target_arch = "wasm32"))]
pub mod theme_store_plugin;
pub mod time_attack_plugin;
pub mod touch_selection_plugin;
pub mod ui_focus;
pub mod ui_modal;
pub mod ui_theme;
pub mod ui_tooltip;
pub mod weekly_goals_plugin;
pub mod whats_new_plugin;
pub mod win_summary_plugin;
pub mod you_hub_plugin;
pub use achievement_plugin::{AchievementPlugin, AchievementsResource, AchievementsScreen};
#[cfg(not(target_arch = "wasm32"))]
pub use analytics_plugin::{AnalyticsPlugin, AnalyticsResource};
pub use animation_plugin::{ActiveToast, AnimationPlugin, CardAnim, ToastEntity, ToastQueue};
pub use assets::{
AssetSourcesPlugin, DARK_THEME_MANIFEST_URL, USER_THEMES, bundled_theme_url,
populate_embedded_dark_theme, register_theme_asset_sources,
};
#[cfg(not(target_arch = "wasm32"))]
pub use audio_plugin::{AudioPlugin, AudioState, SoundLibrary};
pub use auto_complete_plugin::AutoCompletePlugin;
#[cfg(not(target_arch = "wasm32"))]
pub use avatar_plugin::{AvatarFetchEvent, AvatarPlugin, AvatarResource};
pub use card_animation::{
AnimationChain, AnimationTuning, BufferedInput, CardAnimation, CardAnimationPlugin,
DEAL_INTERVAL_SECS, DIAG_WINDOW_SIZE, FrameTimeDiagnostics, HoverState, InputBuffer,
InputPlatform, MAX_DURATION_SECS, MIN_DURATION_SECS, MotionCurve, compute_duration, micro_vary,
sample_curve,
};
pub use card_plugin::{
CardEntity, CardImageSet, CardLabel, CardPlugin, HintHighlight, HintHighlightTimer,
RightClickHighlight, RightClickHighlightTimer,
};
pub use challenge_plugin::{
CHALLENGE_UNLOCK_LEVEL, ChallengeAdvancedEvent, ChallengePlugin, challenge_progress_label,
};
pub use cheat_sheet_plugin::{CheatSheetOverlay, CheatSheetPlugin};
pub use contextual_tips_plugin::ContextualTipsPlugin;
pub use core_game_plugin::CoreGamePlugin;
pub use cursor_plugin::CursorPlugin;
pub use daily_challenge_plugin::{
DailyChallengeCompletedEvent, DailyChallengePlugin, DailyChallengeResource,
};
pub use diagnostics_hud::DiagnosticsHudPlugin;
pub use difficulty_plugin::{DifficultyIndexResource, DifficultyPlugin};
pub use events::{
AchievementUnlockedEvent, CardFaceRevealedEvent, CardFlippedEvent, DrawRequestEvent,
ForfeitEvent, ForfeitRequestEvent, FoundationCompletedEvent, GameWonEvent, HelpRequestEvent,
HintVisualEvent, InfoToastEvent, ManualSyncRequestEvent, MoveRejectedEvent, MoveRequestEvent,
NewGameRequestEvent, PauseRequestEvent, StartChallengeRequestEvent,
StartDailyChallengeRequestEvent, StartDifficultyRequestEvent, StartPlayBySeedRequestEvent,
StartTimeAttackRequestEvent, StartZenRequestEvent, StateChangedEvent,
ToggleAchievementsRequestEvent, ToggleLeaderboardRequestEvent, ToggleProfileRequestEvent,
ToggleSettingsRequestEvent, ToggleStatsRequestEvent, UndoRequestEvent, WinStreakMilestoneEvent,
XpAwardedEvent,
};
pub use feedback_anim_plugin::{
FeedbackAnimPlugin, FoundationFlourish, FoundationMarkerFlourish, SettleAnim, ShakeAnim,
deal_stagger_delay, deal_stagger_secs_for_speed, foundation_flourish_scale, settle_scale,
shake_offset,
};
pub use font_plugin::{FontPlugin, FontResource};
pub use game_plugin::{
ConfirmNewGameScreen, GameMutation, GameOverScreen, GamePlugin, GameStatePath, RecordingReplay,
ReplayPath,
};
pub use help_plugin::{HelpPlugin, HelpScreen};
pub use home_plugin::{HomePlugin, HomeScreen};
pub use hud_plugin::{
ActionButton, HelpButton, HudAutoComplete, HudPlugin, HudVisibility, MenuButton, MenuOption,
MenuPopover, ModeOption, ModesButton, ModesPopover, NewGameButton, PauseButton, StreakFlourish,
UndoButton, streak_flourish_scale,
};
pub use input_plugin::InputPlugin;
pub use layout::{Layout, LayoutResource, compute_layout};
#[cfg(not(target_arch = "wasm32"))]
pub use leaderboard_plugin::{LeaderboardPlugin, LeaderboardResource, LeaderboardScreen};
pub use onboarding_plugin::{OnboardingPlugin, OnboardingScreen};
pub use pause_plugin::{ForfeitConfirmScreen, PausePlugin, PauseScreen, PausedResource};
pub use platform::{PlatformTime, StorageBackend};
pub use play_by_seed_plugin::{PlayBySeedPlugin, PlayBySeedScreen};
pub use profile_plugin::{ProfilePlugin, ProfileScreen};
pub use progress_plugin::{LevelUpEvent, ProgressPlugin, ProgressResource, ProgressUpdate};
pub use radial_menu::{
RadialIcon, RadialMenuPlugin, RightClickRadialState, Z_RADIAL_MENU,
legal_destinations_for_card, radial_anchor_for_index, radial_hovered_index,
};
pub use replay_overlay::{
ReplayOverlayBannerText, ReplayOverlayPlugin, ReplayOverlayProgressText, ReplayOverlayRoot,
ReplayStopButton, Z_REPLAY_OVERLAY,
};
pub use replay_playback::{
REPLAY_COMPLETION_LINGER_SECS, REPLAY_MOVE_INTERVAL_SECS, ReplayPlaybackPlugin,
ReplayPlaybackState, start_replay_playback, stop_replay_playback,
};
pub use resources::{
DragState, GameStateResource, HintCycleIndex, SettingsScrollPos, SyncStatus, SyncStatusResource,
};
pub use safe_area::{SafeAreaAnchoredTop, SafeAreaInsets, SafeAreaInsetsPlugin};
pub use selection_plugin::{
KeyboardDragState, SelectionHighlight, SelectionPlugin, SelectionState,
};
pub use settings_plugin::{
PendingWindowGeometry, SFX_STEP, SettingsChangedEvent, SettingsPlugin, SettingsResource,
SettingsScreen, WINDOW_GEOMETRY_DEBOUNCE_SECS,
};
pub use solitaire_data::SyncProvider;
pub use solution_playback_plugin::{SolutionPlayback, SolutionPlaybackPlugin, SolutionSolveTask};
pub use splash_plugin::{SplashAge, SplashPlugin, SplashRoot};
pub use stats_plugin::{
LatestReplayPath, ReplayHistoryResource, ReplayNextButton, ReplayPrevButton,
ReplaySelectorCaption, SelectedReplayIndex, StatsPlugin, StatsResource, StatsScreen,
StatsUpdate, WatchReplayButton, format_replay_caption,
};
#[cfg(not(target_arch = "wasm32"))]
pub use sync_plugin::{SyncPlugin, SyncProviderResource};
#[cfg(not(target_arch = "wasm32"))]
pub use sync_setup_plugin::SyncSetupPlugin;
pub use table_plugin::{
BackgroundImageSet, HintPileHighlight, PileMarker, TableBackground, TablePlugin,
};
pub use theme::{
ActiveTheme, CardTheme, CardThemeLoader, ThemeEntry, ThemePlugin, ThemeRegistry,
ThemeRegistryPlugin, set_theme,
};
#[cfg(not(target_arch = "wasm32"))]
pub use theme_store_plugin::{ThemeStorePlugin, ThemeStoreScreen};
pub use time_attack_plugin::{
TIME_ATTACK_DURATION_SECS, TimeAttackEndedEvent, TimeAttackPlugin, TimeAttackResource,
};
pub use touch_selection_plugin::{TouchSelectionPlugin, TouchSelectionState};
pub use ui_focus::{Disabled, FocusGroup, Focusable, FocusedButton, UiFocusPlugin};
pub use ui_modal::{
ButtonVariant, ModalActions, ModalBody, ModalButton, ModalCard, ModalHeader, ModalScrim,
UiModalPlugin, spawn_modal, spawn_modal_actions, spawn_modal_body_text, spawn_modal_button,
spawn_modal_header,
};
pub use ui_tooltip::{Tooltip, UiTooltipPlugin};
pub use weekly_goals_plugin::{WeeklyGoalCompletedEvent, WeeklyGoalsPlugin};
pub use whats_new_plugin::{WhatsNewPending, WhatsNewPlugin, WhatsNewScreen};
pub use win_summary_plugin::{
ScreenShakeResource, SessionAchievements, WinSummaryPending, WinSummaryPlugin, format_win_time,
};
pub use you_hub_plugin::{ActiveYouTab, YouHubPlugin, YouHubScreen, YouTab};