ZAYX logo
XGitHubDiscordReddit

Crypto Orbit

A gesture-driven crypto pay button with an orbiting arc of coins. Press and hold to reveal a fan of crypto coin bubbles — drag to hover over any coin, release to select. Each bubble springs out with a staggered reveal, glows and scales when hovered, and the whole interaction runs entirely on the UI thread via a single worklet-side distance check.

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

Gesture-driven coin reveal

Press-and-hold morphs the button into an orbiting arc with a staggered spring reveal, no pre-baked animation.

Radial hit-testing

Drag anywhere on screen; the nearest coin within hitRadius highlights live as your finger moves, powered by a worklet-side distance check.

Active-coin glow & scale

The hovered coin scales up and glows via its own glowColor, driven entirely on the UI thread.

Headless hook included

useCoinGesture exposes the raw gesture and shared values separately for teams building a fully custom coin-picker UI.

Installation

Copy the command directly into your project.

npx degit ManasCodeXart/ZAYX/components/crypto-orbit components/crypto-orbit

Install the needed dependencies

npx expo install react-native-reanimated react-native-worklets react-native-gesture-handler expo-haptics

Use in your app

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

import { StyleSheet } from 'react-native' import { GestureHandlerRootView } from 'react-native-gesture-handler' import { SafeAreaView } from 'react-native-safe-area-context' import CryptoPaySelector from '../../components/crypto-orbit/components/CryptoPaySelector' import { Coin } from '../../components/crypto-orbit/constants/types' export default function WalletScreen() { const handleSelectCoin = (coin: Coin) => { } return ( <GestureHandlerRootView style={styles.root}> <SafeAreaView style={styles.safe}> <CryptoPaySelector onSelect={handleSelectCoin} /> </SafeAreaView> </GestureHandlerRootView> ) } const styles = StyleSheet.create({ root: { flex: 1, }, safe: { flex: 1, backgroundColor: '#000000', }, })

API

<CryptoPaySelector>

PropTypeDefaultDescription
coinsreadonly Coin[]built-in 5-coin set (SOL, BTC, ETH, ADA, BNB)Coins revealed around the button on press-and-hold.
idleLabelstring'Pay'Label shown on the button while idle.
hitRadiusnumberverticalScale(80)Touch radius in points used to detect which coin is under the finger.
hapticsEnabledbooleantrueEnables impact haptics on hover and selection.
showBackdropbooleantrueDims the screen behind the coins while the selector is active.
backdropColorstring'#000000'Color of the dimming backdrop.
bottomOffsetnumber0Extra bottom spacing for the button, e.g. to sit above a tab bar.
onActiveChange(isActive: boolean) => voidFires whenever the selector opens or closes.
onSelect(coin: Coin) => voidRequired. Fires when the user releases their finger over a coin.
containerStyleStyleProp<ViewStyle>Style override for the outer container.
buttonStyleStyleProp<ViewStyle>Style override for the button.
labelStyleStyleProp<TextStyle>Style override for the button label.

useCoinGesture(params)

Headless hook powering CryptoPaySelector. Use it directly if you want to render the coin arc yourself with a completely custom visual layer.

Params

PropTypeDefaultDescription
coinsreadonly Coin[]Required. Coins to hit-test against.
hitRadiusnumberverticalScale(80)Touch radius in points.
hapticsEnabledbooleantrueEnables impact haptics on hover and selection.
onSelect(coin: Coin) => voidRequired. Fires on release over a coin.
onActiveChange(isActive: boolean) => voidFires on gesture begin/end.

Returns

FieldTypeDescription
gestureGestureTypePass to <GestureDetector gesture={gesture} >.
activeIndexSharedValue<number>Index of the currently hovered coin, -1 if none.
activeCoinIdstring | nullJS-thread mirror of activeIndex, for use outside worklets.
revealProgressSharedValue<number[]>Per-coin reveal progress, 0–1.
backdropOpacitySharedValue<number>Backdrop fade progress, 0–1.
buttonLayoutSharedValue<CoinPosition>Measured screen position of the button, used as the hit-test origin.

Types

interface Coin { readonly id: string; readonly name: string; readonly symbol: string; readonly glowColor: string; readonly icon: ImageSourcePropType; readonly position: CoinPosition; } interface CoinPosition { readonly x: number; readonly y: number; }

Project Structure

crypto-orbit/
├── components/
│ ├── CryptoPaySelector.tsx # Root component — press-and-hold coin reveal
│ └── CoinBubble.tsx # Per-coin render node, memoized
├── constants/
│ ├── defaultCoins.ts # Built-in 5-coin starter set (SOL, BTC, ETH, ADA, BNB)
│ ├── types.ts # Coin, CoinPosition types
│ └── index.ts # Barrel export
├── hooks/
│ └── useCoinGesture.ts # Pan gesture + shared-value orchestration, headless
├── utils/
│ ├── geometry.ts # Radial position calculations
│ ├── scaling.ts # verticalScale helpers
│ └── index.ts # Barrel export
└── assets/