fix(engine): restore 60 fps Android card animations + dead-code sweep #166

Merged
funman300 merged 2 commits from fix/android-anim-redraw into master 2026-07-09 18:51:07 +00:00
Owner

Android animation lag (Rhys's report — v0.40.0 regression)

Commit 38e4c03 switched Android's focused_mode to reactive_low_power(100 ms) on the premise that every animation tick system writes RequestRedraw while active. The writers never landed — the diff only contained the WinitSettings change, imports, and add_message registrations. With no touch input, nothing woke the winit loop during a card slide except the 100 ms fallback ceiling, so animations rendered at ~10 fps. Desktop/web keep Continuous mode, which is why the jank was Android-only and animation-only (drags stayed smooth — touch events drive frames). Matches the bisect evidence: absent on v0.39.1, present since v0.40.0 (released the day of the first report).

This adds the missing MessageWriter<RequestRedraw> to all seven systems the original commit message named (card animations, deal/win-cascade slides, shake, settle, foundation flourish, toast countdown, auto-complete keepalive), each writing one redraw per frame while it has active work — including delay phases. Regression test: active_card_animation_requests_redraw (idle board emits nothing; active animation emits every frame).

Dead-code sweep (multi-agent audit)

Compiler-verified (--force-warn dead_code) + workspace-wide reference greps; −1,145 lines:

  • replay_overlay/input.rs: ~950 lines of orphaned twins of items also defined in mod.rs (glob re-export made the mod.rs copies win; a file-level #![allow(dead_code)] hid them). Live handlers preserved; allow retired.
  • retarget_animation, ScanThemesRequestEvent (its doc claimed a nonexistent consumer), _VEC3_REFERENCED hack, data-crate default-path wrappers (load_stats/save_stats/time_attack_session_with_now), surplus re-exports, ReplayPlayer::is_finished, build_app.
  • Doc fixes: audio_plugin (WAV count, missing FoundationCompletedEvent row, 'placeholder' label, bevy_kira_audiokira), ToastVariant::Warning stale allow removed (variant is live).

Deliberately kept, pending owner decision: Spider module (staged forward work), WinCascadePlugin, SyncCompleteEvent, solitaire_sync::ApiError/merge_at (§8-gated).

Verification

  • cargo test --workspace: all suites green (928 engine tests incl. new regression test)
  • cargo clippy --workspace --all-targets -- -D warnings: clean
  • On-device: needs a release tag for the Fold 7 / Rhys verification that card slides are smooth again

🤖 Generated with Claude Code

## Android animation lag (Rhys's report — v0.40.0 regression) Commit 38e4c03 switched Android's `focused_mode` to `reactive_low_power(100 ms)` on the premise that every animation tick system writes `RequestRedraw` while active. **The writers never landed** — the diff only contained the WinitSettings change, imports, and `add_message` registrations. With no touch input, nothing woke the winit loop during a card slide except the 100 ms fallback ceiling, so animations rendered at ~10 fps. Desktop/web keep `Continuous` mode, which is why the jank was Android-only and animation-only (drags stayed smooth — touch events drive frames). Matches the bisect evidence: absent on v0.39.1, present since v0.40.0 (released the day of the first report). This adds the missing `MessageWriter<RequestRedraw>` to all seven systems the original commit message named (card animations, deal/win-cascade slides, shake, settle, foundation flourish, toast countdown, auto-complete keepalive), each writing one redraw per frame while it has active work — including delay phases. Regression test: `active_card_animation_requests_redraw` (idle board emits nothing; active animation emits every frame). ## Dead-code sweep (multi-agent audit) Compiler-verified (`--force-warn dead_code`) + workspace-wide reference greps; −1,145 lines: - **replay_overlay/input.rs**: ~950 lines of orphaned twins of items also defined in mod.rs (glob re-export made the mod.rs copies win; a file-level `#![allow(dead_code)]` hid them). Live handlers preserved; allow retired. - `retarget_animation`, `ScanThemesRequestEvent` (its doc claimed a nonexistent consumer), `_VEC3_REFERENCED` hack, data-crate default-path wrappers (`load_stats`/`save_stats`/`time_attack_session_with_now`), surplus re-exports, `ReplayPlayer::is_finished`, `build_app`. - Doc fixes: audio_plugin (WAV count, missing `FoundationCompletedEvent` row, 'placeholder' label, `bevy_kira_audio`→`kira`), `ToastVariant::Warning` stale allow removed (variant is live). Deliberately kept, pending owner decision: Spider module (staged forward work), `WinCascadePlugin`, `SyncCompleteEvent`, `solitaire_sync::ApiError`/`merge_at` (§8-gated). ## Verification - `cargo test --workspace`: all suites green (928 engine tests incl. new regression test) - `cargo clippy --workspace --all-targets -- -D warnings`: clean - On-device: needs a release tag for the Fold 7 / Rhys verification that card slides are smooth again 🤖 Generated with [Claude Code](https://claude.com/claude-code)
funman300 added 2 commits 2026-07-09 18:50:17 +00:00
Commit 38e4c03 (shipped in v0.40.0) switched Android's focused_mode to
reactive_low_power(100 ms) on the premise that every animation tick
system writes RequestRedraw while it has active work. The writers were
never actually added — the diff only contained the WinitSettings change,
imports, and add_message registrations. Result: with no touch input,
nothing wakes the winit loop during a card slide except the 100 ms
fallback ceiling, so animations render at ~10 fps on Android. Desktop
and web keep Continuous mode, which is why only Android was affected
(reported by Rhys the day v0.40.0 shipped; confirmed absent on v0.39.1).

Adds the missing MessageWriter<RequestRedraw> to all seven systems the
original commit message named:
- advance_card_animations (CardAnimationPlugin)
- advance_card_anims (AnimationPlugin — deal/win cascade/slides)
- tick_shake_anim, tick_settle_anim, tick_foundation_flourish
  (FeedbackAnimPlugin)
- drive_toast_display (AnimationPlugin — toast countdown)
- drive_auto_complete (AutoCompletePlugin — step-interval keepalive)

Each writes one RequestRedraw per frame while active work exists
(including delay phases, which also need per-frame ticks). Regression
test asserts an active CardAnimation emits RequestRedraw and an idle
board does not.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Compiler-verified via RUSTFLAGS=--force-warn dead_code plus workspace-wide
reference greps; three parallel audit agents covered the engine crate, the
other eight crates, and Copilot commit-message-vs-diff drift.

Removed:
- replay_overlay/input.rs: 19 orphaned twins (~950 lines) of items also
  defined in mod.rs — the glob re-export made the mod.rs copies win and
  the file-level #![allow(dead_code)] hid the corpses. The live keyboard/
  button handlers and ReplayScrubKeyHold stay; the allow is retired.
- retarget_animation (never called; doc examples were its only refs)
- ScanThemesRequestEvent (never registered/written/read; its doc claimed
  a handle_scan_themes consumer that does not exist)
- _VEC3_REFERENCED workaround const + now-unneeded Vec3 import
- solitaire_data: load_stats/save_stats/time_attack_session_with_now
  default-path wrappers (the _from/_to variants are the live API) and
  surplus re-export names (settings MIN/MAX bounds, token loaders)
- solitaire_core: Session re-export (no external consumer)
- solitaire_wasm: ReplayPlayer::is_finished (no JS caller)
- solitaire_app: build_app wrapper (real entry is run())

Doc fixes:
- audio_plugin: WAV count 5→7, add FoundationCompletedEvent table row,
  drop bogus 'placeholder' label, bevy_kira_audio→kira
- ToastVariant::Warning: variant is live (5 writer plugins); dropped the
  stale allow(dead_code) and its 'currently unused' comment

Deliberately kept: Spider module (staged forward work), WinCascadePlugin
(documented alternative cascade, pending owner decision), SyncCompleteEvent
and solitaire_sync ApiError/merge_at (§8 change-controlled, flagged to owner).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
funman300 merged commit ede58f9666 into master 2026-07-09 18:51:07 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: funman300/Ferrous-Solitaire#166