Skip to content

Reduce per-move gameplay lag - #70

Merged
austin-smith merged 4 commits into
mainfrom
reduce-per-move-gameplay-lag
Jul 15, 2026
Merged

austin-smith merged 4 commits into
mainfrom
reduce-per-move-gameplay-lag

Conversation

@austin-smith

Copy link
Copy Markdown
Owner

What Changed

  • Replaced the whole-board .animation(value: viewModel.state) with the same spring scoped per board region (header, top row, tableau, TriPeaks, Pyramid, Canfield), each keyed on the state slice that region renders, so one move no longer opens an animation transaction over the entire board.
  • Made CardView equatable (the card's tilt participates as a value captured at init) so cards whose rendered inputs are unchanged skip body re-evaluation.
  • Moved the debounced autosave's sanitize and JSON encode (up to 200 undo snapshots) off the main thread. Only the SwiftData write remains on the main actor, and a superseded encode is skipped instead of written. The pure game-model layer is now nonisolated to make the background encode legal under the project's MainActor-by-default isolation.
  • Gated FreeCell's auto-finish availability on a single-pass cascade-ordering check, a necessary condition for the foundation run, so the greedy win simulation no longer executes on every move.
  • Moved AutoFinishPlanner from Game/Klondike/ to Game/Shared/ since it serves five variants.
  • Bumped the marketing version to 0.8.1.

Why

Noticeable click-to-response lag on macOS during ordinary moves (drawing from the stock in TriPeaks was the repro). Every move armed a 350 ms spring across the whole board, re-evaluated every card view, and later ran a main-thread sanitize and encode of the full undo history. FreeCell additionally simulated a complete greedy win on every move just to enable the Auto Finish button.

Validation

  • macOS build clean and the full unit suite passes, including two new tests covering the FreeCell gate (rejects a same-suit misordered burial, passes cross-suit burials through to the simulation).
  • The hint-probe still compiles and runs against the annotated model layer.
  • Manually verified on macOS and the iOS simulator: TriPeaks draw flight with mid-air flip, peak plays, the Klondike three-card fan, tableau-to-foundation auto-moves, game switching, and a kill-and-relaunch restore written by the background autosave.
  • Visible behavior is unchanged, including the header score/moves spring and all card art.

scope the board move spring per region (header, top row, tableau,
tripeaks, pyramid, canfield) keyed on the state slice each renders, so
one move no longer opens an animation transaction over the whole board.
make cardview equatable so cards whose rendered inputs are unchanged
skip re-evaluation; the card's tilt participates as a value captured at
init since the binding defeats swiftui's memberwise diff.
move the debounced autosave's sanitize and json encode (up to 200 undo
snapshots) off the main thread, leaving only the swiftdata write on the
main actor; the pure game-model layer is marked nonisolated to make the
background encode legal under the project's mainactor-by-default
isolation.
the planner serves klondike, yukon, freecell, forty thieves, and
canfield; it never belonged in the klondike folder.
freecell's candidate check was unconditionally true, so every move ran
a full greedy win simulation on the main thread just to decide whether
the auto-finish button should enable. require same-suit cards within
each cascade to sit in foundation order first — a necessary condition
for the foundation run that rejects nearly every mid-game position in
a single pass, and one the run's own moves can never invalidate, so
availability behaves exactly as before.
@cursor

cursor Bot commented Jul 15, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@austin-smith
austin-smith merged commit 027815f into main Jul 15, 2026
2 checks passed
@austin-smith
austin-smith deleted the reduce-per-move-gameplay-lag branch July 15, 2026 00:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant