ZAYX logo
XGitHubDiscordReddit

Coin Reward

Drag-to-spin coin toss with a Skia scratch card reveal.

Open in Github
Open in ChatGPT
Open in Claude
Open in Cursor

Drag-to-spin coin toss

Velocity and translation both feed into flip triggering; a light tap or slow drag just settles back without launching a flip.

Skia-powered scratch reveal

GPU-rendered erase-as-you-scratch overlay over a real Canvas, with grid-based coverage tracking that auto-completes once enough of the card is scratched clear.

Two-moment callback API

onFlipComplete fires the instant the coin lands, onRevealComplete fires once the reward is scratched clear; wire analytics and reward-unlock logic to each separately.

Fork-and-edit reward content

RevealContent ships as a clearly-marked placeholder; swap in your own cashback, coupon, or prize UI directly rather than fighting a config API.

Installation

Copy the command directly into your project.

npx degit ManasCodeXart/ZAYX/components/coin-reward components/coin-reward

Install the needed dependencies

npx expo install react-native-reanimated react-native-worklets react-native-gesture-handler @shopify/react-native-skia lottie-react-native

Use in your app

Built to match the preview exactly — for the complete implementation, check the repo on GitHub.

import { GestureHandlerRootView } from "react-native-gesture-handler"; import FlipReveal from "../../components/coin-reward/components/FlipReveal"; export default function Screen() { return ( <GestureHandlerRootView> <FlipReveal onFlipComplete={(face) => console.log('flip complete', face)} onRevealComplete={(face) => console.log('reward revealed', face)} /> </GestureHandlerRootView> ) }

API

<FlipReveal>

The batteries-included flow — coin toss into scratch card, wired together with correctly-derived timing.

PropTypeDefaultDescription
onFlipComplete(face: CoinFace) => voidCalled when the coin lands, before the scratch card appears.
onRevealComplete(face: CoinFace) => voidCalled once the scratch card is fully scratched and the reward is revealed.

<CoinFlip>

PropTypeDefaultDescription
onResult(face: CoinFace) => voidCalled when the coin finishes settling after a flip.

<ScratchCard>

PropTypeDefaultDescription
faceCoinFace | nullWhich face's reveal content to render underneath the scratch layer.
visiblebooleanControls open/close. Animates in on true, slides out on false.
onDismiss() => voidCalled when the user taps outside the card to dismiss it.
onFullyRevealed() => voidCalled once the scratch coverage threshold is crossed and the overlay finishes fading out.

<Coin>

PropTypeDefaultDescription
faceCoinFaceWhich face to render.
sourceImageSourcePropTypebundled artworkOverride the artwork for this face. Tails artwork should stay forward-facing — CoinFlip applies the 180° mirror via rotateY, so a pre-mirrored image renders backwards.
styleStyleProp<ViewStyle>Style override for the coin container.

Customizing Reward Content

RevealContent renders whatever sits under the scratch layer and is meant to be edited directly rather than configured through props — swap HeadsReveal / TailsReveal in components/RevealContent.tsx for your own cashback, coupon, or prize UI.

Types

type CoinFace = 'heads' | 'tails';

Project Structure

coin-reward/
├── components/
│ ├── FlipReveal.tsx # Root component — coin toss into scratch card
│ ├── CoinFlip.tsx # Drag-to-spin coin toss
│ ├── Coin.tsx # Per-face coin artwork
│ ├── ScratchCard.tsx # Skia scratch-to-reveal overlay
│ └── RevealContent.tsx # Reward content — edit this directly
├── constants/
│ └── types.ts # CoinFace type
└── assets/