Dropped frames on low-end devices amplify discomfort
Aliases: dropped frames · jank · stutter · low-end animation
What it is
Once motion starts, vision predicts the next position as continuous travel. If a low-end device misses vsync, frames drop: motion becomes a stuttered jump. That unsmoothness is worse than the same animation running slower but on time—the prediction breaks, rather than speed falling. Discomfort is amplified because the device cannot hold the frame budget, not because a property does or doesn’t trigger layout, and not because a degrade switch exists.
Why it happens
At 60 Hz a frame has about 16.7 ms; 120 Hz is tighter. If style, layout, paint, composite, and app script overrun, the frame is skipped and the object appears at C instead of interpolating through B. Vision reads that as a pop, not as the missing in-between. Low-end CPU/GPU, thermal throttle, and background cores make overruns more frequent. The same transform motion that stays on the compositor on a flagship can still drop frames on a low-end device if too many layers, a huge blur, or JS occupying the main thread.
Distribution matters. Drops at the start, then a smooth tail, get the whole clip labeled “janky.” Periodic misses every few frames feel more like flicker than a single miss. Large, high-contrast motion through the point of fixation makes drops more visible. So low-end discomfort is continuity punched full of holes, not the mean FPS number.
Studying it
In the lab, use a frame timeline to see missed vsync and whether long frames sit inside the animation window; reproduce on devices with fewer cores, limited GPU, or thermal throttle. In the field, RUM should count long frames or drops during animation, by device percentile—not mean FPS on a lab flagship. High lab frame rate and a low-end field tail often metric mismatch: the lab is focused and cool, the field is throttled and multi-tab. Outcomes: drop count, longest frame, input delay during the clip. Mean FPS hides the tail. Whether the animation lays out is a different leaf’s factor; here record only whether frames were on time.
Where it stops holding
A progress indicator the user is watching as wait can survive an occasional drop better than freezing entirely. Cinematic 24 fps content is not expected to interpolate at 60. Off-screen or background tabs usually stop compositing, so there is nothing to drop. On a high-refresh panel a missed frame is shorter, so the same count may feel milder—but flagship 120 Hz headroom is not a low-end 60 Hz budget. Instantaneous state changes with no frame sequence do not use this discomfort mechanism.
Applying it
- Run real motion on the target low-end device (hot, old, core-limited), not only on a development machine that “looks smooth.”
- Keep long main-thread work out of the animation window: parsing and image decode should not share frames with the transition.
- Cut large blurs, stacked shadows, and excess
will-changelayers on low-end first—they spend the composite budget even when they do not layout. - Verify with a frame timeline on the low-end device: long frames during the transition should be near zero. Field drop percentiles by device should fall after those cuts. Pretty mean FPS with a living p95 long-frame is not a pass.