Devlog: holding 60fps on a five-year-old phone
Most of our players are not on a flagship. Here is the performance budget we hold every release to, and the three things that kept breaking it.

We test on a 2020 mid-range Android device before we test on anything newer. If the game does not hold a steady frame rate there, it does not ship — regardless of how it runs on the newest hardware.
The budget
- Cold start under one second to an interactive screen
- Steady 60fps during play, no frame longer than 20ms
- Install size small enough to download on mobile data without hesitation
- Idle battery draw close to zero when the game is open but untouched
Three things that kept breaking it
Layout thrash on every drag. Reading an element's position during a drag forces the browser to recalculate layout mid-frame. We now read positions once when a drag begins and cache them.
Shadows on moving elements. A soft box-shadow on a dragged piece was costing us more than the rest of the frame combined. Replacing it with a pre-rendered sprite fixed it entirely.
Garbage collection during runs. We were allocating a fresh array every frame to hold the highlighted cells. Reusing one array across frames removed the periodic hitches players were reporting as "stutter every few seconds".
None of this is clever. It is just measuring first, then fixing the thing the measurement actually points at.

