About this animation
A trial paywall with a comet tracing day-by-day portals, with configurable timeline steps, copy, colors, and fonts.
Why this one
The trial becomes a journey toward full access while the reminder, charge date, and cancellation terms remain explicit. The finish is a restrained light reveal rather than a modal or confetti effect.
How it works
- Measure the container and reserve foreground space for the billing terms and actions.
- Drive the comet and three portal reveals from shared journey progress.
- Draw the nebula in a bounded Skia shader region while keeping copy in native layout.
- Let portal taps and
focusStep(index)interrupt that same progress;replay()restarts the presentation. - Show the completed journey immediately with reduced motion and leave purchases to the host callback.
Install
npx expo install expo-blur expo-linear-gradient react-native-gesture-handler react-native-reanimated react-native-worklets @shopify/react-native-skiaPlace the component inside a GestureHandlerRootView. Copy TrialTimelinePaywall.tsx, icons.ts, and index.ts together. No assets or application imports are required. Expo Go must include the listed native modules; otherwise use a development build.
Usage
import { useRef } from 'react';
import TrialTimelinePaywall, { type TrialTimelinePaywallRef } from './trial-timeline-paywall';
const paywall = useRef<TrialTimelinePaywallRef>(null);
<TrialTimelinePaywall
ref={paywall}
title="A new world awaits."
priceLead="7 days free, then"
price="$29.99/year ($2.49/mo)"
onStart={beginTrial}
onClose={dismiss}
/>Pass loaded font family names through fontFamily, boldFontFamily, titleFontFamily, and monoFontFamily. The demo uses Geist, Instrument Serif at 1.18×, and Geist Mono. The component falls back to the platform font.
Props
| Prop | Default | Purpose |
|---|---|---|
title | A new world awaits. | Editorial heading. |
steps | Today, Day 5, Day 7 | Milestone content and portal colors. Designed for three milestones. |
priceLead | 7 days free, then | Trial and billing lead-in. |
price | $29.99/year ($2.49/mo) | Billing text. A leading dollar amount is emphasized; narrow proportional punctuation keeps the amount tight, and billing terms share its baseline. |
ctaLabel | Begin my free trial | Primary action and accessible label. |
footerLinks | ['Promo code', 'Restore purchases'] | Footer action labels. |
colors | Deep navy, cool blue, warm gold | Existing background, glow, and cta theme controls. |
startDate | Current date | Billing date is seven calendar days later. |
locale | en-US | Locale for the billing date. |
fontFamily | Platform font | Interface font. |
boldFontFamily | Interface font | Milestone and action font. |
titleFontFamily | Interface font | Editorial heading font. |
monoFontFamily | Platform font | Portal days, eyebrow, and price font. |
eyebrow | YOUR NEXT CHAPTER | Small brand/category text. Hidden in short containers. |
closeLabel | Close paywall | Accessible close action label. |
onStart, onClose, onPromoCode, onRestore | — | Action callbacks; this component does not perform purchases. |
style, testID | — / trial-timeline-paywall | Container styling and test identifier. |
Each TrialTimelineStep retains title, description, icon, colors, and optional chargeDate. Supported Lucide icons: rocket, bell, credit-card, x. Set optional dayLabel to control the number in the portal; otherwise the number is inferred from the heading or index. A chargeDate description replaces {date} with the calculated date.
The existing ref exposes replay() and focusStep(index). Focusing a portal interrupts the same shared progress used by the comet; the plan stays readable. Invalid indices are clamped; nonfinite indices are ignored.
Compatibility
Expo SDK 58 / React Native 0.88 / Reanimated 4.7 / Skia 2.14. The atmospheric shader is restricted to a container-width × 240-point region with two noise octaves; stars share a static path, and glow strokes avoid animated blur filters. All frame updates run on the UI thread. The glass card and its BlurView both have explicit radius and clipping; Android uses a BlurTargetView with the SDK 31+ blur method and a translucent fallback on older devices.
Icons: Lucide, ISC license.
Accessibility
The composition measures its container, caps foreground content at 480 points, and uses no nested scroll views. The nebula spans the full container width and fades to transparency at its top and bottom. The scene receives the remaining vertical space; milestone descriptions stay in normal flow with a 16-point gap before billing. Descriptions use 13-point text with an 18-point line height. Short containers use a compact billing row and show the focused milestone title and description below the portals. Tap another portal to read its description; screen readers receive every milestone's full description independently.
Portal targets are at least 56 × 56, the CTA is at least 48 points high, and secondary controls are at least 44 points high. Gesture Handler handles portal/CTA taps and accessibility activation runs the same callbacks. Pressure feedback uses an interruptible spring with explicit mass 1, damping 28, and stiffness 240 (ζ ≈ 0.90).
Reduced motion shows the completed journey immediately and removes the comet, shockwaves, parallax, and sheen. Focus changes use a short transition. Demo autoplay replays through the public ref every 6.5 seconds and stops after touch or pointer input.




