Selecting a row jumped the camera instead of easing to it. The shared helper
spread FLY_CONFIG into the fitBounds call, which looks like it animates and does
not: FLY_CONFIG carries speed and curve, which flyTo understands and fitBounds
ignores. Without an explicit duration, fitBounds is an instant cut. The flyTo
paths in the same file were always eased, which is why the tree rows animated and
the map did not -- different mechanisms, not one broken setting.
Measured before: the camera moved 1.45 to 6 with two distinct zoom values across
fourteen samples. After: it interpolates through 1.453, 1.806, 3.429.
options still spreads last, so a caller passing duration 0 still jumps. That is
why the default lives here rather than in FLY_CONFIG, which is shared with
callers that must not inherit it.
One thing this box cannot settle: whether 900ms FEELS right. Sampling with
requestAnimationFrame returned six frames in 1.6 seconds -- SwiftShader software
rendering paints at roughly 4fps here, so perceived smoothness is not measurable
on this machine and my earlier "hard cut" reading at 90ms intervals was aliasing
against a starved renderer. The easing is proven present; the duration is a
judgement for a real browser.