Stage 1 · roll axis only

Keep the window
level with the world.

Gravity is the reference. The accelerometer reads which way is down — absolutely, without drift. The gyroscope fills the gaps between those readings, because gravity gets buried in noise the moment the phone is moving.

Browsers disagree about which gyroscope channel carries which axis, so the first thing this does is watch your motion and work it out. Rock the phone side to side when it asks.

deg roll
axis —
Accel
Gyro int
Zoom
Rate Hz
Gravity clean
Roll observable
Response

Presets for the two sliders below. Instant tracks your hand hard and lets a little sensor noise through.

0.25 s

How long the filter takes to pull back onto gravity. Short is snappy and shakier; long is glassy and lags.

45 ms

Extrapolates forward along the current turn rate to cancel the sensor‑to‑screen delay. Set it near your measured pipeline latency: too much and fast flicks overshoot and snap back.

Angle source

Accelerometer anchors the angle, gyroscope smooths it. This is the one you ship.

Gyro roll channel

Detecting…

The spec puts the screen-normal rate in α, but WebKit maps its channels straight onto CoreMotion's x/y/z, so on iOS it lands in γ and α carries pitch. Auto settles it by correlating each channel against the accelerometer's own roll rate.

Framing
Content & gravity

Gravity sign: normal.