About this animation
An upgrade-to-payment flow linked by a traveling lightning bolt, with configurable plan, payment methods, colors, and fonts.
Why this one
The purchase has a visual thread: the same dimensional bolt rests on a glass card, rises when payment clears, and opens the welcome horizon. Selection uses one moving gradient outline instead of three disconnected highlights. Light is drawn into the scene and bolt material, rather than swept across the copy.
How it works
onLayoutmeasures the host; a centered column caps the width at 440 pt. The screen uses normal text flow and scrolls in short containers or with large text.- A full-container radial gradient fades seamlessly into the background. One persistent hero scene draws the Lucide bolt with a warm gradient, edge highlight, and offset extrusion. The bolt breathes from 0.8 to 1 every 2.4 seconds, then shrinks and rises for checkout using the shared step progress.
- Row layouts drive a single outline's position and height through a critically damped spring. A separate shared value animates each radio.
- Gesture Handler taps give immediate pressure feedback on a separate shared value. Callbacks cross to JavaScript with
scheduleOnRN. onPay(method)owns the transaction. A fill advances toward 88%, waits for the promise, and completes only on resolution. Rejections leave checkout visible and expose an error and retry.- All three screens stay mounted to preserve their canvases, but inactive panels use
display: none. A shared content opacity finishes a 100 ms outgoing fade before committing the next screen, which then fades in over 160 ms. Interrupted transitions cancel obsolete completions. The header stays at a fixed position independent of panel height, and Back fades within a reserved slot. The success reveal enlarges the same bolt and expands full-container radial light while the receipt appears. Receipt columns settle within 560 ms, with independently sized separators. Payment icons share one persistent Canvas to avoid creating new WebGL contexts on each autoplay loop.
The demo timeline is offer → checkout at 0.6 s → Bank at 1.04 s → Card at 1.44 s → payment at 1.75 s → reveal around 2.57 s → welcome until 6.65 s → repeat. Any touch stops the autoplay timers; an already-started payment can finish.
Install
npx expo install @shopify/react-native-skia expo-blur expo-linear-gradient react-native-gesture-handler react-native-reanimated react-native-workletsCopy this folder without demo/. Wrap your app in GestureHandlerRootView and configure Reanimated/Worklets for your Expo project. For web, load CanvasKit before importing this component (Skia's WithSkiaWeb/deferred loader). Load your chosen fonts in the host. No remote assets or internal catalog imports are required.
Usage
import { GlowTierUpgrade } from './glow-tier-upgrade';
<GlowTierUpgrade
plan={{ name: 'Premium', price: 124, benefits: ['Priority support', 'Travel benefits', 'Higher limits'] }}
methods={[{ id: 'card', name: 'Card', detail: '•••• 4821 · exp 03/28', icon: 'credit-card' }]}
receipt={{ purchased: 'Premium · Annual', billedTo: 'Card', date: '10/14/2026' }}
onPay={async (method) => { await submitPayment(method.id); }}
onSettings={() => openCardSettings()}
/>Controlled selection and personality:
<GlowTierUpgrade
ref={upgradeRef}
plan={plan}
methods={methods}
method={selectedMethod}
onMethodChange={setSelectedMethod}
onPay={payForPlan}
receipt={receipt}
fontFamily="Geist_400Regular"
monoFontFamily="GeistMono_400Regular"
labels={{ title: 'Your next\nchapter', upgrade: 'Explore premium' }}
theme={{ accent: ['#7954E8', '#F290B2'], gold: '#FFE4B2' }}
glowIntensity={0.7}
revealDuration={560}
/>upgradeRef.current?.goTo('offer' | 'payment' | 'welcome') changes screens. await upgradeRef.current?.pay() invokes the payment adapter; the welcome reveal follows asynchronously. Never use this component as the source of truth for payment authorization.
Props
| Prop | Type | Default | Purpose |
|---|---|---|---|
plan | UpgradePlan | Required | Name, major-unit price, and benefit strings |
methods | PaymentMethod[] | Required | IDs, names, details, and kit icon names |
method | string | First method, internally | Controlled selection |
onMethodChange | (id) => void | — | Selection callback |
onPay | (method) => Promise<void> | Required | Transaction adapter |
receipt | UpgradeReceipt | Required | Purchased, billed-to, and formatted date fields |
labels | Partial<UpgradeLabels> | Generic English copy | Every visible structural label and action |
theme | Partial<UpgradeTheme> | Night violet | Background, surface, text, muted text, borders, accent, gold, glow, brand, and button text |
brandName | string | Membership | Wordmark with the kit sparkle tile |
fontFamily | string | System | Interface font |
monoFontFamily | string | System | Amount font |
formatPrice | (number) => string | Dollar, two decimals | Currency display and receipt digit string |
onStepChange | (UpgradeStep) => void | — | Committed screen callback |
onError | (unknown) => void | — | Adapter error callback |
onInteraction | () => void | — | User contact notification |
onSettings | () => void | — | Welcome CTA action |
revealDuration | number | 560 | Success sequence duration, ms |
glowIntensity | number | 0.85 | Ambient opacity, 0–1 |
style | StyleProp<ViewStyle> | flex: 1 | Host layout |
testID | string | glow-tier-upgrade | Stable root/control IDs |
Theme colors used for translucent materials must be six-digit hex strings. Supply a complete palette when switching to a light theme. The host owns safe-area insets; this is an embeddable flow, not a navigator. Methods and benefits can grow vertically. No raster images are used.
Compatibility
Targets Expo SDK 58, React Native 0.88.0, Reanimated 4.7.1, Worklets 0.13.0, Gesture Handler 3.3, and Skia 2.14.0. Uses installed Expo Go modules. Android 12+ uses BlurTargetView with the SDK 58 blur API; older Android versions use the translucent material fallback.
Accessibility
Actions expose button roles and radios expose selected state, labels, and accessibility activation. Important screen and transaction changes are announced. Controls are at least 48 pt high. Reduced motion removes the ambient loop, bolt travel, radial flash, and digit rolling, with sequential 150 ms outgoing and incoming screen fades. Text remains in flow and keeps system font scaling. Receipt amounts have one spoken label.
Icons: Lucide (ISC). Demo identity: Aster from the repository kit; no payment network logos.
Implementation notes
Copy uses explicit line heights and normal flow. The header reserves 72 pt on the right for the catalog close control; actions sit below or on the left. At 390×844 the column stays full size; 320×694 uses the compact hero and checkout, and smaller hosts scroll rather than squeezing hit targets. The offer card ends before the headline block. Autoplay begins the payment flash within three seconds. The header starts at the same 24 pt inset in every step, with a permanent 48 pt Back slot. Inactive panels cannot paint or intercept touches. Light comes from the bolt shader and full-container radial gradients; no rectangular shine passes over text.




