KVADRANT UI api reference demo

KvadrantPanorama

navigation

the long horizontal canvas, with its title parallaxing behind the sections

dark
light

mounted as panorama

why it looks like this

A single surface wider than the screen, panned sideways, with a title too big to fit and a background that drifts behind it.

The numbers are the ones in Microsoft.Phone.dll's own template, and two of them correct a long-standing confusion: the panorama title is 170 px PhoneFontFamilyLight at -35/1000 em of tracking, while the section header is 66 px SemiLight. They are different elements two levels apart, and treating the title as 72 px SemiLight — which is what the brief said — makes it less than half the size it should be.

The parallax rates are derived, not chosen. Each layer has more width than the viewport and has to finish traversing its own overflow exactly when the content finishes traversing its own. So a layer's rate is its overflow divided by the content's, which is what the original's pair of TranslateTransforms does and the reason the effect holds at any number of sections.

It wraps, and wrapping is what makes the parallax rates derivable. Past the last section comes the first, as the original does with its LeftWraparound and RightWraparound borders: the sections are laid out twice and the scroll position is folded back by one copy's width whenever it crosses into the second.

That fold is invisible only for a layer that is periodic with the same fold. This used to offset each layer by scroll rate with the layer drawn once, so at every fold the background snapped sideways by copyWidth rate — a distance that is a period of nothing. The paragraph here claimed "never a jump to see" and there was one, on every wrap; the title escaped notice only because a title narrower than the viewport had its rate coerced to zero and did not move at all.

The correct model is a set of cylinders. Scrolling one content copy has to advance each layer by exactly one of its own circumferences, so a layer's rate is its own period over the content's — not a coefficient anybody gets to pick. Each layer is drawn twice and offset modulo its period, and the fold then lands on a seam that is identical to where it started.

Right-to-left costs this component nothing either, and the reason is Modifier.offset (B-41). Every layer here is placed by that modifier rather than by a hand-written place, and it mirrors its x on its own — so a mirrored page pans the layers the other way with no code for it, which MirroredTravelTest measures as a sign rather than trusting. The pivot's header strip is the one that needed a change, because it places its children itself. Said here so that the next person asking about right-to-left re-checks one layout instead of three.

The title is the one layer that is not a cylinder, because the original says so: it "does not repeat itself when you pan past the edges of the content", and instead leaves and re-enters at the selection change that crosses the edge. So it is drawn once, travels its own overflow exactly once across a copy, and the seam it would otherwise have is the transition — titleTransition, and B-33.

Read it: kvadrant-core/src/commonMain/kotlin/io/github/youndie/kvadrant/components/KvadrantPanorama.kt · the full signature and every parameter