ZAYX logo
XGitHubDiscordReddit

Coins Screen Transition

A tap-to-fullscreen coin morph with seamless shared-element transitions. Tap a coin in a scrollable list and it springs from its exact on-screen position into a large floating detail view — no hardcoded coordinates, correct even mid-scroll. Closing squashes the coin back to its origin with a spring rebound instead of snapping back flat.

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

Card-to-fullscreen morph

Measures the coin's live position via a UI-thread-safe measure() call, then springs it from its exact origin to a centered floating view; works correctly at any scroll position.

Squash-and-settle close

Springs the coin back to its origin, then layers a vertical squash-and-rebound on landing instead of a flat snap-back.

Staggered reveal

Overlay fades in first, coin springs to target scale, detail content only fades in once the coin has settled, so nothing competes for attention at once.

Transition-safe taps

A coin tap is ignored while a morph is already in flight, so rapid double-taps can't desync the animation mid-transition.

Installation

Copy the command directly into your project.

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

Install the needed dependencies

npx expo install react-native-reanimated react-native-worklets

Use in your app

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

import { StyleSheet, View } from 'react-native' import CoinMorphList from '../../components/coin-morph/components/CoinMorphList' import { MOCK_COINS } from '../../components/coin-morph/constants/mockcoins' import { verticalScale } from '../../components/coin-morph/constants/scaling' const Index = () => { return ( <View style={styles.container}> <CoinMorphList coins={MOCK_COINS} /> </View> ) } export default Index const styles = StyleSheet.create({ container: { flex: 1, paddingTop: verticalScale(300), backgroundColor: '#000', }, })

API

<CoinMorphList>

PropTypeDefaultDescription
coinsreadonly Coin[]Required. Coins rendered in the horizontal list.
renderDetail(coin: Coin) => ReactNodeRenders inside the fading detail container once the morph settles. Fully decoupled from the coin animation.
overlayColorstringbackground colorBackground color behind the floating coin and detail content.

<AnimatedCounter>

PropTypeDefaultDescription
valuenumberRequired. Target number to animate to.
prefixstringPrepended to the formatted value e.g. '$'.
suffixstringAppended to the formatted value.
decimalsnumberDecimal places shown.
durationnumberAnimation duration in ms.
delaynumberDelay before the count-up starts, in ms.
styleStyleProp<TextStyle>Style applied to the underlying Text.

Types

interface Coin { readonly id: string; readonly name: string; readonly price: number; readonly image: ImageSourcePropType; } interface CoinOrigin { readonly x: number; readonly y: number; } interface CoinMorphAnimation { readonly overlayOpacity: SharedValue<number>; readonly coinScale: SharedValue<number>; readonly coinTranslateX: SharedValue<number>; readonly coinTranslateY: SharedValue<number>; readonly coinSquashY: SharedValue<number>; readonly detailOpacity: SharedValue<number>; }

Project Structure

coin-morph/
├── components/
│ ├── CoinMorphList.tsx # Root component — list + morph orchestrator
│ ├── CoinList.tsx # Horizontal scrollable coin row
│ ├── CoinListItem.tsx # Card: coin image, name, AnimatedCounter price
│ └── CoinDetailModal.tsx # Floating coin morph + overlay + detail content
├── constants/
│ └── types.ts # Coin, CoinOrigin, CoinMorphAnimation types
├── hooks/
│ └── useCoinDetailModal.ts # Morph animation state + transition logic
└── assets/