Improve win cascade animation performance - #100
Conversation
the cascade was driven by a task.sleep loop stepping a fixed 1/60s per tick, so any dropped frame stretched the animation into slow motion, and each of the 52 cards rendered as a live swiftui view with its own per-frame shadow blur — the dominant gpu cost that caused the drops in the first place. the physics now advances by real elapsed time off a timelineview frame clock (native 120 hz on promotion), and the overlay renders as a single canvas that resolves each card face once as a symbol and stamps it with a per-frame transform. the extra cascade-only drop shadow is removed so flying cards match resting cards exactly; settled cards skip simulation entirely, and the canvas size feeds the physics bounds so mid-cascade resizes track.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5f963c54af
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
the tick previously clamped measured frame deltas to [1/120, 1/30]s, which discarded time beyond 33ms on slow frames and fabricated time on displays above 120hz. advance() now splits real frame time into <=1/60s substeps so simulated time matches wall time at any refresh rate, capped at 133ms per frame so a long stall jumps ahead instead of fast-forwarding.
|
@codex review |
|
Codex Review: Didn't find any major issues. 👍 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
What Changed
Task.sleeploop (fixed 1/60s step) with atickdriven byTimelineView(.animation)'s frame clock that advances the physics by real measured elapsed time, clamped by the existing step bounds.WinCascadeOverlayViewto render the whole cascade as a singleCanvas: each card face resolves once as a Canvas symbol and is stamped with a per-frame translate/rotate transform, replacing 52 liveCardViews with per-card layout, diffing, and shadow blurs.@ObservationIgnoredso per-frame mutation cannot schedule redundant SwiftUI updates; a new observablelaunchStatessnapshot drives symbol creation. Cascade completion defers the phase flip off the render pass, guarded by a generation token.cancelTask()(the timeline stops itself when the view disappears).Why
The win animation could visibly lag and slow down. Two compounding causes: the fixed-timestep loop turned every dropped frame into slow motion (real time passed faster than simulated time), and the per-card live shadow blurs were the dominant GPU cost producing those dropped frames. The rework fixes the timing model and collapses rendering to one draw pass per frame, and the animation now runs at the display's native cadence (120 Hz on ProMotion).
Validation
UI Changes
Flying cascade cards no longer gain an extra drop shadow beyond the card artwork's own — they now match resting cards exactly. Motion timing is otherwise visually identical, minus the lag.