First-run pages as color posters with arch windows, where parallax and progress follow your finger.
Paged onboarding on a horizontal scroll view: two-layer parallax and a continuously filling progress pill that follow the finger, with Continue morphing into Get started.
$199 once, every piece included. See how installing works · Sign in
SwiftUI source you own, built on Apple frameworks only.
artworkonFinish handoffOnboarding (screen)
How it behaves, what it handles, and the decisions behind it.
Pages live in a horizontal ScrollView with .scrollTargetBehavior(.paging) instead of a paged TabView, so scrollTransition actually fires and the hero's two depth layers (a tinted disc moving fast, the symbol moving slower) track the drag frame by frame. The progress pill fills continuously from the scroll offset, Continue morphs into Get started on the last page, and a selection haptic marks each page settle. Skip sits top-trailing until the last page.
scrollPosition(id:) is the source of truth for the settled page; the offset is read from a named coordinate space so it works on iOS 17.continueTitle, finishTitle, skipTitle); pass skipTitle: nil to hide Skip..glassProminent on iOS 26.layout: .poster draws each page as a solid block poster (OnboardingPoster) with an arch window of scenery, the page number in the corner, story segments beside Skip and a 60pt Continue. The default .fullBleed is unchanged.artwork: draws a page's own art over the foot of the artwork, given the page and its index, so product UI can sit on onboarding pages without assets.OnboardingStackExample at the end of OnboardingStack.swift is the Welcome screen from the preview: Cadence's pages on .poster with habit rows, a streak card and a reminder as artwork, handing off to a Today screen.SPTheme from @Environment(\.spTheme), so it needs the design-system item. Set .environment(\.spTheme, PaperTheme()) or your own theme once at the root.fill track, textPrimary fill) and the Continue button (accent tint, accentOn label) all come from the theme.OnboardingPage tint is optional. Leave it nil and the hero follows theme.color.accent; pass a color to keep a per-page tint.theme.color.bg or let OnboardingFlowScreen paint it.Pieces that work well next to this one.