| Primary alternates rapidly between two adjacent items while scrolling slowly | stability | Raise hysteresisPx (start 24, range 10-50): a challenger must be closer to the anchor than the incumbent by this many px |
| Fast fling fires a barrage of primary changes | stability | Set minPrimaryDuration (start 150ms, range 100-250): incumbent holds at least this long while it stays focused |
| Primary switches feel sluggish/sticky after tuning | stability | Lower the two values above; or set preferCurrentPrimary: false to always take the best candidate each pass (subject only to min duration) |
| Autoplay pauses between cards; primary goes null when the region falls in a gap | stability | Keep allowPrimaryWhenNoItemFocused: true (default): keeps a best-available primary for gapless playback |
| TOC/reading UI highlights a section when nothing is truly under the line | stability | Set allowPrimaryWhenNoItemFocused: false: primary becomes null the moment nothing intersects the region (strict semantics) |
| Focus drops out between items even while one is clearly nearby | region | Zone too thin: raise extentPx (item-extent-sized zones behave well); or switch a line to a zone |
| Two items both "look focused" and the winner feels arbitrary | policy | Pick the policy that matches intent: closestToAnchor (feeds), largestVisibleFraction (galleries), largestFocusOverlap, largestFocusProgress; ties break deterministically by focusProgress, then visibleFraction, then distance, then registration order |
| Primary lags the finger during drag, corrects on settle | update policy | That is onScrollEnd/hybrid semantics; use perFrame (default) for live tracking |
| Updates during scroll are wanted only at rest (impressions, autoplay-on-settle) | update policy | onScrollEnd(debounce: 80ms); state is intentionally stale mid-scroll |
| Rebuild pressure from metric listeners during flings | update policy | hybrid(ballisticInterval: 50ms): per-frame while dragging, throttled ballistic, guaranteed settle pass |
| First/last items can never win with a centered anchor | geometry | Symmetric list padding of (viewportExtent - itemExtent) / 2 (the official demo technique), or bias the anchor (fraction(0.4), or offsetPx) |
| Tuning "randomly resets" while scrolling | config churn | onScrollEnd(...)/hybrid(...) have no const constructors and no ==; constructing them inline in build makes every rebuild a config change. Build once, store in a field |