Zoom is now constant. The previous build rescaled the content by how far it had shifted, so every movement pulsed the image — a 60 px shift meant a 1.31× zoom. That was most of the glitching, and it had nothing to do with the sensors.
There is a live trace under the readouts. If something still jumps, it will jump there too, and you can tell me which signal does it.
Calibration runs first: rock the phone side to side, then tilt it forward and back.
Linear acceleration source: detecting…
Fixed keeps the zoom constant no matter what — movement is limited to the margin instead. Adaptive rescales to always cover, which is what made the image pulse. Compare them and you will see immediately which one you were fighting.
Hard limit on how far the window can travel from centre. The integrator is bounded to this too, so it can never wind up past the edge and then lag on the way back.
The gyroscope predicts the acceleration your rotation must have caused, a = α×s + ω×(ω×s), and only the remainder counts as movement. Manual by default now, because a twitchy auto fit modulates the rejection and that itself looks like glitching. Auto is worth a try once the rest feels solid.
Velocity is forced to zero when the phone is genuinely still. Exit threshold is twice this, so it cannot chatter at the boundary — chattering was flipping the position decay several times a second.
Accelerometer anchors the angle, gyroscope smooths it. This is the one you ship.
Detecting…
Gravity sign: normal.