perf(engine): rebuild card children only on appearance change #112

Merged
funman300 merged 1 commits from fix/card-move-anim-jank into master 2026-06-26 19:03:19 +00:00
Owner

Problem

Rhys reported the card move animation is janky on a Galaxy Fold 7 (not general lag — specifically the slide).

Root cause: every move fires StateChangedEvent -> sync_cards, which rebuilt the full visual for all 52 cards — despawning and respawning every child entity (drop-shadow, border frame, and on Android a Text2d corner label needing a glyph re-layout) even for the ~50 cards that did not move. That ~250 entity despawn/spawns plus 52 text re-layouts in a single frame spikes the StateChangedEvent frame and stutters the short slide animation, very visible on a high-resolution display.

Fix

Add a CardChildrenKey component capturing the only inputs the child entities depend on (face_up, card_size, color_blind, high_contrast). update_card_entity now rebuilds children only when that key changes (a flip, resize/fold, or accessibility toggle); a position-only move just updates the Transform. The Sprite is still refreshed every sync (a cheap handle swap), so theme/card-back image changes need no child rebuild.

Result: a typical move touches children for only the 0-1 cards that actually flipped, instead of all 52.

Adds a regression test asserting an appearance-neutral StateChangedEvent no longer despawns/respawns card label children. Workspace clippy + tests green.

Helps universal Android performance; Rhys to confirm the on-device improvement on the Fold 7.

🤖 Generated with Claude Code

## Problem Rhys reported the card **move animation is janky** on a Galaxy Fold 7 (not general lag — specifically the slide). Root cause: every move fires `StateChangedEvent` -> `sync_cards`, which rebuilt the full visual for **all 52 cards** — despawning and respawning every child entity (drop-shadow, border frame, and on Android a `Text2d` corner label needing a glyph re-layout) even for the ~50 cards that did not move. That ~250 entity despawn/spawns plus 52 text re-layouts in a single frame spikes the `StateChangedEvent` frame and stutters the short slide animation, very visible on a high-resolution display. ## Fix Add a `CardChildrenKey` component capturing the only inputs the child entities depend on (`face_up`, `card_size`, `color_blind`, `high_contrast`). `update_card_entity` now rebuilds children **only when that key changes** (a flip, resize/fold, or accessibility toggle); a position-only move just updates the `Transform`. The `Sprite` is still refreshed every sync (a cheap handle swap), so theme/card-back image changes need no child rebuild. Result: a typical move touches children for only the 0-1 cards that actually flipped, instead of all 52. Adds a regression test asserting an appearance-neutral `StateChangedEvent` no longer despawns/respawns card label children. Workspace clippy + tests green. Helps universal Android performance; Rhys to confirm the on-device improvement on the Fold 7. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
funman300 added 1 commit 2026-06-26 19:03:00 +00:00
Every move fired StateChangedEvent -> sync_cards, which rebuilt the full
visual for all 52 cards: despawning and respawning every child entity
(drop-shadow, border frame, and on Android a Text2d corner label needing
a glyph re-layout) even for the ~50 cards that did not move. That ~250
entity despawn/spawns plus 52 text re-layouts in a single frame spiked
the StateChangedEvent frame and stuttered the slide animation on
high-resolution devices (reported on a Galaxy Fold 7).

Add a CardChildrenKey component capturing the only inputs the child
entities depend on (face_up, card_size, color_blind, high_contrast).
update_card_entity now rebuilds children only when that key changes (a
flip, resize/fold, or accessibility toggle); a position-only move just
updates the Transform. The Sprite is still refreshed every sync (a cheap
handle swap), so theme/card-back image changes need no child rebuild.

Adds a regression test asserting an appearance-neutral StateChangedEvent
no longer despawns/respawns card label children.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
funman300 merged commit 0247efcb07 into master 2026-06-26 19:03:19 +00:00
funman300 deleted branch fix/card-move-anim-jank 2026-06-26 19:03:20 +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#112