Every draw-from-stock tap was also firing the HUD auto-hide toggle
because the stock pile is not an ActionButton and toggle_hud_on_tap
had no way to know the tap was consumed by game logic.
Add GameInputConsumedResource(bool): handle_touch_stock_tap sets it
on TouchPhase::Started when a draw fires; toggle_hud_on_tap checks
and clears it on TouchPhase::Ended, treating it as equivalent to
started_on_button so the HUD stays put.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace per-call new_current_thread() runtimes with a single
TokioRuntimeResource(Arc<Runtime>) built once at startup using
new_multi_thread(worker_threads(2)). The Arc is cloned cheaply into
each AsyncComputeTaskPool closure, eliminating repeated OS thread
allocation on every sync pull/push, auth, avatar fetch, and analytics
flush. Using a multi-threaded runtime ensures concurrent block_on calls
from different worker threads are safe.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
P0 fixes:
- Register WinSummaryPlugin, SelectionPlugin, CardAnimationPlugin in main.rs
(all three were exported but never wired — features silently did nothing)
- game_state::draw(): increment move_count on waste→stock recycle, not just
on normal draws; add move_count_increments_on_recycle regression test
P1 fixes:
- solitaire_server/Cargo.toml: remove duplicate dev-dependencies
(solitaire_sync, uuid, chrono, jsonwebtoken were in both sections)
P2 — input_plugin refactor:
- Split 198-line handle_keyboard() into three focused systems under 110 lines each:
handle_keyboard_core (U/N/Z/D/Space), handle_keyboard_hint (H), handle_keyboard_forfeit (G)
- Introduce KeyboardConfirmState resource to share countdown timers across systems
- Add three new unit tests: all_hints_suggests_draw_*, all_hints_is_empty_when_truly_stuck,
new_game_confirm_window_is_positive
P2 — achievement predicate tests (solitaire_core):
- Add 10 direct unit tests for speed_demon, lightning, no_undo, high_scorer,
on_a_roll, comeback predicates (previously only covered via check_achievements())
- 141 core tests now passing
P2 — server tests:
- solitaire_server/src/sync.rs: 4 unit tests for merge logic (no DB required)
- solitaire_server/src/leaderboard.rs: 2 unit tests for entry shape and sort order
P3 — documentation:
- Add struct-level /// to 12 Plugin structs (ChallengePlugin, CursorPlugin,
AnimationPlugin, HelpPlugin, PausePlugin, AudioPlugin, DailyChallengePlugin,
HudPlugin, LeaderboardPlugin, OnboardingPlugin, TimeAttackPlugin, WeeklyGoalsPlugin)
- Add field-level /// to Card, Pile, Deck, GameState, AchievementContext, AchievementDef
- Add /// to WeeklyGoalKind, WeeklyGoalDef, WeeklyGoalContext, StatsExt::update_on_win
card_animation module (new files from previous session):
- chain.rs, diagnostics.rs, tuning.rs, updated interaction.rs/animation.rs/mod.rs/lib.rs
- Remove unused HOVER_SCALE_DEFAULT / DRAG_LIFT_SCALE_DEFAULT / HOVER_LERP_SPEED_DEFAULT constants
- Add handle_touch_stock_tap so touch users can draw from the stock pile
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Round 7 — Input & feedback
- H key cycles hints; F1 opens help (conflict resolved)
- N key cancels active Time Attack session
- Hint text distinguishes "draw from stock" vs "recycle waste"
- Forfeit (G) clears AutoCompleteState so chime does not bleed into new deal
- Zen mode timer clears immediately on Z press
- HUD shows recycle count in both draw modes
- Settings scroll position persisted across open/close
Round 8 — Polish & clarity
- Undo unavailable fires "Nothing to undo" toast
- Streak-break toast on forfeit/abandon when streak > 1
- F11 fullscreen toggle with toast; documented in help and home screens
- H-after-win, new-game countdown expiry, Tab-no-cards toasts
- Win cascade duration/stagger scales with animation speed setting
- Draw-Three cycle counter HUD ("Cycle: N/3")
- Forfeit requires G×2 confirmation within 3 s (mirrors N key)
Round 9 — Game feel & information
- Escape dismisses game-over/stuck overlay (PausePlugin skips Escape when overlay visible)
- Shake animation on rejected drag before snap-back
- Forfeit countdown cancels when any other key is pressed (U/H/D/Z/Space)
- Tab wrap-around fires "Back to first card" toast
- HUD selection indicator shows active Tab-selected pile in yellow
- Challenge time-limit HUD turns orange < 60s, red < 30s
- Win summary shows XP breakdown (+50 base, +25 no-undo, +N speed)
- Game-over overlay: "No more moves available" with clear N/Escape/G instructions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Introduces the plumbing layer for Phase 3: GameStateResource wraps
solitaire_core::GameState, DragState tracks in-progress drags, and
SyncStatusResource holds runtime sync status. GamePlugin routes
Draw/Move/Undo/NewGame request events into GameState and emits
StateChangedEvent and GameWonEvent for downstream systems.
Also adds the Phase 3 implementation plan under docs/superpowers/plans/.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>