Skip to content
Native Animation
Mascot Paywall animation preview
Onboarding

Mascot Paywall

A premium subscription paywall where the mascot responds to plan choices and celebrates purchase intent.

$9 for this animation

Checkout opens soon. Leave your email and we will tell you the moment you can buy it.

One email when checkout opens. No spam.

Add to your project

Copy the component and its assets into your app with the Native Animation CLI, or paste the agent prompt into Claude Code, Codex or Cursor once the MCP server is connected.

npx nativeanimation add mascot-paywall

About this animation

A premium subscription paywall where the mascot responds to plan choices and celebrates purchase intent.

Why this one

Most mascot paywalls treat the character as decoration. Here, the mascot breathes and blinks at rest while Lucide stars orbit the hero. Plan selection changes its brows, cheeks, tilt, and pose with an interruptible spring. Pressing the CTA triggers a focused 520 ms jump, stretching shadow, halo, and particle burst in the selected plan's accent, making the conversion moment feel earned without delaying checkout.

How it works

  1. onLayout measures the component so the mascot, typography, cards, and celebration scale inside any parent instead of depending on the window.
  2. A continuous selection shared value connects each plan card to the mascot's pose and expression; tapping another card springs every dependent property from its current value.
  3. The selected plan owns the single accent used by the hero, controls, checks, CTA glow, mascot cheeks, and celebration particles.
  4. pressCta() runs a short UI-thread sequence: the mascot jumps, its shadow stretches, a halo expands, and ten particles travel outward before fading.
  5. The component keeps checkout behavior on the JS thread through callbacks, while the forwarded ref gives demos and host apps deterministic control.

Install

npx expo install @expo/vector-icons expo-image expo-linear-gradient react-native-reanimated

Usage

import MascotPaywall from './MascotPaywall';

export function UpgradeScreen() {
  return (
    <MascotPaywall
      mascot={require('./assets/mascot.png')}
      onCtaPress={() => openCheckout()}
    />
  );
}

Customize the plans, copy, fonts, and accent while keeping the same interaction model:

import { useRef } from 'react';
import MascotPaywall, { type MascotPaywallRef } from './MascotPaywall';

export function UpgradeScreen() {
  const paywallRef = useRef<MascotPaywallRef>(null);

  return (
    <MascotPaywall
      ref={paywallRef}
      mascot={require('./assets/mascot.png')}
      brand="Daymark"
      tier="Plus"
      headline={['Build a ', 'brighter', ' learning habit']}
      accentColor="#6E56FF"
      plans={[
        {
          badge: 'Flexible',
          title: 'Monthly',
          subtitle: 'Billed monthly',
          price: '$7.99',
          period: '/ month',
        },
        {
          badge: 'Save 58%',
          title: 'Yearly',
          subtitle: 'Billed $39.99 yearly',
          price: '$3.33',
          period: '/ month',
        },
      ]}
      onPlanChange={(index, selectedPlan) =>
        trackPlan(index, selectedPlan.title)
      }
      onCtaPress={() => openCheckout()}
    />
  );
}

The forwarded ref exposes selectPlan(index), pressCta(), and celebrate().

Icons: Lucide/Feather (ISC).

Props

PropTypeDefaultDescription
mascotImageSourcePropTypeRequiredTransparent mascot image displayed in the hero.
brandstring'Brightpath'Product name.
tierstring'Plus'Paid tier label.
headline[string, string, string]['Grow a little ', 'brighter', ' every day']Headline before, inside, and after the accented segment.
planPaywallPlanMonthly offerBackward-compatible first plan when plans is omitted.
plansPaywallPlan[]Monthly and YearlySelectable subscription plans.
initialPlanIndexnumber1Initially selected plan, clamped to the available range.
featuresPaywallFeature[]Three learning benefitsBenefits shown in the premium surface.
ctaLabelstring'Start 7 days free'Main action label.
notestring'No charge today · Cancel anytime'Reassurance below the CTA.
moreLabelstring'Choose a plan'Accessible label for the plan group.
accentColorstring'#6E56FF'Default accent for selection, checks, glow, and particles.
topColors[string, string]Accent-derivedOptional hero gradient override.
sparkColorstringSelected accentOptional mascot cheek and sparkle color.
fontFamilystringSystem fontInterface and supporting-text family.
titleFontFamilystringSystem fontHeadline, plan-title, and price family.
onCtaPress() => void—Called after the CTA celebration starts.
onClose() => void—Called when Close is pressed.
onMorePress() => void—Legacy callback called when a plan is selected.
onPlanChange(index, plan) => void—Called with the newly selected plan.
styleStyleProp<ViewStyle>—Outer-container style.
testIDstring—Test identifier for the outer container.

PaywallPlan accepts badge, title, subtitle, strikePrice, price, period, and an optional accentColor.

Compatibility

  • Expo SDK 57
  • React Native 0.86
  • Reanimated 4.5
  • iOS: supported, not yet verified on a device
  • Android: supported, not yet verified on a device
  • Web: supported, not yet visually verified
  • Works in Expo Go because the required native modules are included in the SDK

Accessibility

The close and CTA controls expose button roles and labels. Plans are presented as a labeled radio group, and every plan reports its selected state and price. Reduce Motion replaces spring-driven reactions and travel with short fades while keeping plan selection and the CTA fully functional.