# Crypto Wallet: React Native crypto trading flow (Robinhood-style build) > Crypto Wallet is a complete React Native and Expo build from Motionary: a > three-screen crypto trading flow (discover, token, swap) with a Skia price > chart you scrub with a finger and an odometer amount display whose digits > roll one glyph at a time, all driven from shared values on the UI thread with > Reanimated 4 so a scrubbing finger never crosses onto the JS thread. Product page: https://motionary.dev/builds/crypto-wallet Price: $49 USD (price as of 2026-09-01, live price on the product page) License: single developer, unlimited personal and commercial apps Delivery: instant download of the full TypeScript source after checkout Stack: expo, react native, react native skia, reanimated Sold by: Motionary (https://motionary.dev) ## What it is Crypto Wallet is a Motionary build: a whole React Native and Expo app, not a single component. It is modelled on Robinhood's crypto tab and traced frame by frame from a recording of the original. Three screens ship inside it: a discover page (trending rail, "Today's lists" chips, a ranked token list and a floating search pill over a gradient scrim), a token page (live quote header, Skia price chart, seven range tabs, stats and a Buy button that arrives after the page does), and a swap sheet (token pills, the animated amount, a unit toggle, quick-amount chips and a custom keypad) sitting on a full-bleed canvas that paints a soft violet trail wherever you touch. You drag a finger along the chart to read a price off the line, and you type an amount on a keypad that is not the system keyboard, so every character can be animated individually. ## What it does - Three screens and the two transitions between them, wired in `Container.tsx`: discover pushes the token page in, the token page presents the swap sheet. - Push transition traced from the original: a spring at zeta ~= 0.94, omega0 ~= 16.7 rad/s that decelerates into the edge without bouncing, with the outgoing page sliding 0.2995 of the screen behind it. - Swap sheet rises on a spring and dismisses on a 260ms timing curve, unmounted only once it is off screen so its canvas and frame callback stop running. - Drag-to-read chart scrub that snaps a crosshair to the nearest sample and keeps the index, the crosshair x and the fade entirely in shared values. - Skia chart with three layers: a plain path for the line, a 120pt vertex-coloured glow ribbon laid along a 15-station smoothed spine, and a live marker that pings on its own steady 2s beat. - Two glow palettes: indigo to teal to olive for a range that closed up, and indigo to magenta to red for a range that closed below its open. - Seven ranges (LIVE, 1D, 1W, 1M, 3M, 1Y, 5Y), each built from a seeded PRNG so the chart is byte-identical on every launch, all pinned to finish on the same quote. - A live quote feed on uneven 260 to 900ms intervals; ticks that round to the same cent leave the display alone. - Odometer amount display: characters slide in and out through a clip band about one line tall, at full size, with no scaling and no fading. - Ducking commas (opt-in `dipSeparators`): every separator falls out through the bottom of the band and springs back together on each reflow. - Rolls tinted green or red by direction on the token page, draining back to cream over 900ms. - Custom 3x4 keypad with per-key press springs and a light haptic on any press that actually changes the value; the bottom-right key is MAX until something is typed, then backspace. - Amount state machine with no leading zeros, one decimal point, and capped integer (15) and fraction (2) digits. - Full-screen paint trail that captures touches without stealing them, so you can scribble across the keypad and still type. - iOS and Android, with a web bootstrap that loads CanvasKit before the first Skia canvas mounts (`loadSkiaWeb.ts`). ## How it works The interesting work in Motionary's Crypto Wallet build is that every number that moves lives in a Reanimated shared value, never in React state. `useScrub.ts` is a `Gesture.Pan` with `activeOffsetX([-6, 6])` and `failOffsetY([-14, 14])` so horizontal intent scrubs and vertical intent is left to the scroll view; its `onStart`/`onUpdate` worklets round the touch x to the nearest sample and write the index, the crosshair x and an opacity fade, and the header reads that index back inside its own worklets. Because a finger rewrites the quote on every frame and each rewrite starts a fresh odometer roll (a roll takes about 220ms to land), `usePaced.ts` resamples the value on an 85ms cadence while the finger is down: the metronome is a single `withRepeat(withTiming(...))` whose completion callback is the beat, pinned to `ReduceMotion.Never` so the system reduce-motion setting cannot collapse it and freeze the quote mid-scrub. It is a resample, not a throttle, so it can never leave a stale value behind when a fast finger stops without lifting. The chart itself (`PriceChart.tsx`) is a Skia `` holding a `` for the line and a `` triangle strip for the glow, coloured per vertex from a palette and wrapped in a ``, on a canvas oversized by 70pt on every side so the light falls off past the screen instead of leaving a seam. The amount in `AmountDisplay.tsx` is a run of individually placed Skia `` nodes, each inside a `` whose `transform` comes from a `useDerivedValue` over four shared values (`x`, `baseline`, `fontScale`, `slide`); a `useAnimatedReaction` on the value tokenises it, measures glyph advances from the `SkFont`, centres the run, shrinks it to `maxWidth` and springs every character toward the new solution on one critically damped spring at omega ~= 28 rad/s. It hinges on keying: digits are keyed by index from the left and separators by how many digits sit to their right, so both survive an append and a comma can slide into an existing run. Slots come from a fixed pool of 40 `makeMutable` shared values handed out to characters in a worklet rather than mounted per character, which is what lets the same component render a quote that changes every frame. The change label cannot be a `` (a new string means a React render), so `AnimatedText.tsx` uses a read-only `TextInput` wrapped in `Animated.createAnimatedComponent` and rewrites its animatable `text` prop from `useAnimatedProps`, with an `initial` prop covering the first frame before the native field exists. And `TouchPaint.tsx` captures touches without stealing them: its `Gesture.Pan()` calls `manualActivation(true)` and never activates, observing `onTouchesDown`/`onTouchesMove` from the BEGAN state while the `Pressable`s underneath keep working; points go into a flat array that is replaced rather than mutated (Reanimated hands each worklet its own copy), each stroke is a triangle strip with the alpha on its vertices so the GPU fades the ribbon along its length, and a `useFrameCallback` prunes dead strokes and only advances the clock while something is alive, so an idle screen never repaints. ## What you get ``` App.tsx index.ts loadSkiaWeb.ts app.json babel.config.js package.json package-lock.json tsconfig.json README.md assets/ icon.png adaptive-icon.png splash-icon.png pool.png components/ Container.tsx TabBar.tsx AnimatedText.tsx TouchPaint.tsx Keypad.tsx UnitToggle.tsx theme.ts discover/ DiscoverScreen.tsx TokenMark.tsx data.ts token/ TokenScreen.tsx PriceChart.tsx RangeSelector.tsx useScrub.ts usePaced.ts useLivePrice.ts series.ts format.ts swap/ SwapScreen.tsx amount/ AmountDisplay.tsx layout.ts useAmountInput.ts ``` Included in the Crypto Wallet build from Motionary: - `Container.tsx`, three screens with a traced push transition and a swap sheet - `discover/DiscoverScreen.tsx`, trending rail, list chips, ranked token rows, floating search pill - `token/TokenScreen.tsx`, live quote header, chart, range selector, stats, animated Buy reveal - `token/PriceChart.tsx`, Skia line, vertex-coloured glow ribbon, pulsing live marker, crosshair - `token/useScrub.ts`, drag-to-read gesture that never leaves the UI thread - `token/usePaced.ts`, resamples the quote on a cadence so rolls cannot pile up during a scrub - `token/series.ts` and `token/useLivePrice.ts`, deterministic per-range price series and a live tick feed - `amount/AmountDisplay.tsx`, per-character animated Skia amount, driven from a shared value - `amount/layout.ts`, stable character keys, measuring, centring, shrink-to-fit - `amount/useAmountInput.ts`, value state machine (leading zeros, decimals, MAX, backspace) - `Keypad.tsx`, custom 3x4 keypad with press springs and haptics - `TouchPaint.tsx`, full-screen Skia paint trail driven by a non-blocking touch gesture - `AnimatedText.tsx`, text content rewritten from a worklet, without a React render - `TabBar.tsx`, `UnitToggle.tsx` and `theme.ts`, shared chrome and colours sampled from the original - A README with install, usage and the reasoning behind each animation ## Requirements Versions pinned in the Crypto Wallet build's `package.json`: - `expo` ~56.0.11 (Expo SDK 56) - `react-native` 0.85.3 - `react` 19.2.3 - `react-native-reanimated` 4.3.1 - `react-native-worklets` 0.8.3 - `@shopify/react-native-skia` 2.6.2 - `react-native-gesture-handler` ~2.31.1 - `react-native-safe-area-context` ~5.7.0 - `@expo/vector-icons` ^15.0.3 - `expo-haptics` ~56.0.3 - `expo-linear-gradient` ~56.0.4 - `expo-status-bar` ~56.0.4 - `expo-blur` ~56.0.3 - `expo-font` ~56.0.5 - `expo-asset` ~56.0.14 - `expo-video` ~56.1.4 - `typescript` ~6.0.3 (dev dependency) Expo Go or development build: Crypto Wallet runs in **Expo Go on Expo SDK 56**. The dependency people expect to block it is `@shopify/react-native-skia`, which draws the price chart, the amount glyphs and the paint trail, and it is bundled in Expo Go as of SDK 56. So is every other native dependency the Crypto Wallet build imports: Reanimated 4 with `react-native-worklets`, `react-native-gesture-handler`, `react-native-safe-area-context`, `expo-haptics`, `expo-linear-gradient` and `expo-status-bar`. Run `npx expo start` and open the build in Expo Go. A development build (`npx expo run:ios` or `npx expo run:android`) is still what you would ship to production, and you need one as soon as you add a native module Expo Go does not bundle, or a config plugin of your own. Two practical notes: the keypad's light haptic only fires on a physical device, not a simulator, and the web build needs the `loadSkiaWeb.ts` bootstrap that loads CanvasKit before the first Skia canvas mounts. The app also has React Compiler switched on via `experiments.reactCompiler` in `app.json`, and `babel-preset-expo` wires up the `react-native-worklets` plugin automatically. ## Install ```bash npx expo install @shopify/react-native-skia react-native-reanimated react-native-worklets react-native-gesture-handler react-native-safe-area-context @expo/vector-icons expo-haptics expo-linear-gradient expo-status-bar ``` ## Usage ```tsx import { matchFont } from '@shopify/react-native-skia'; import { useWindowDimensions } from 'react-native'; import { AmountDisplay } from './components/amount/AmountDisplay'; import { BASE_FONT_SIZE } from './components/amount/layout'; import { useAmountInput } from './components/amount/useAmountInput'; import { Keypad } from './components/Keypad'; import { TouchPaint } from './components/TouchPaint'; export const SwapAmount = () => { const { width } = useWindowDimensions(); const font = matchFont({ fontSize: BASE_FONT_SIZE, fontWeight: '400' }); const { shared, press, isEmpty } = useAmountInput({ balance: 1250.5 }); return ( ); }; ``` `AmountDisplay` and `TouchPaint` are independent of the rest of the Crypto Wallet build, so you can drop `TouchPaint` around any screen to get the paint layer, and drive `AmountDisplay` from any `SharedValue`. The token page does exactly that with a derived value off the live feed: ```tsx const priceText = useDerivedValue(() => plain(shown.value)); const flashSign = useDerivedValue(() => scrub.index.value === NO_SCRUB ? live.direction.value : 0, ); ``` ## Customization Props on `AmountDisplay` in Motionary's Crypto Wallet build: - `value: SharedValue` (required), the raw value: `""` renders a placeholder 0, `"1234"`, `"1234.5"`. - `flashSign?: SharedValue`, 1 up, -1 down, 0 for no tint. Read when the value changes, never depended on. - `font: SkFont | null` (required), created once at `BASE_FONT_SIZE` (88) so every glyph is drawn through a scale of 1 or less and stays crisp. - `width: number`, `height: number` (required), the canvas box. - `maxWidth?: number`, defaults to `width`; horizontal room the run may occupy before it starts shrinking. - `color?: string`, defaults to the theme's cream `#EDE6E2`. - `tabular?: boolean`, defaults to `false`; put every digit on a common advance. Off by default because the original uses proportional figures. - `dipSeparators?: boolean`, defaults to `false`; commas duck out through the bottom of the band and rise back on every reflow instead of gliding. - `align?: 'center' | 'left'`, defaults to `'center'`. - `upColor?: string` / `downColor?: string`, default to the theme's `#BAF033` and `#FF4D7B`. - `style?: StyleProp`. Props on `Keypad`: - `onKey: (id: KeyId) => boolean | void` (required); return `false` to signal a no-op press, which skips the haptic. - `trailingKey?: 'backspace' | 'max'`, defaults to `'backspace'`. - `haptics?: boolean`, defaults to `true`. - `style?: StyleProp`. Options on `useAmountInput`: - `maxIntegerDigits?: number`, defaults to 15. - `maxFractionDigits?: number`, defaults to 2. - `balance?: number`, the value the MAX key inserts, defaults to 0. Other configuration in the source: - `TouchPaint` takes only `children` and `style`; the ink lifetime and colour are constants at the top of `TouchPaint.tsx`. - `components/theme.ts` holds every colour sampled from the original, including the two chart glow palettes. - `TabBar.tsx` exports `FOOTER_OFFSET` (68), the single height both floating controls sit at. - `components/token/series.ts` exports `RANGES` with each range's period label, percentage, seed and sample count, so the chart data is edited in one place. ## When to use it - A crypto or stock trading app that needs a token detail page with a scrubbable price chart and a live quote header. - A fintech or banking app where the user types an amount: transfers, top-ups, send money, tipping, a donation screen. - Any checkout or payment sheet that wants a large animated amount instead of a plain `TextInput`, with rolling digits and no visible caret. - A portfolio, wallet or budgeting screen that shows a value moving in real time and needs it to repaint without re-rendering React. - A data or analytics screen where a user drags along a chart to read a value off a specific point. - A reference build for learning how to keep a gesture-driven number entirely on the UI thread with Reanimated 4 and Skia. ## How to get it - Buy the Crypto Wallet build on its own at https://motionary.dev/builds/crypto-wallet, $49 USD, instant download, secure Stripe checkout, no subscription and no account renewal. - Or get it with the **Motionary lifetime pass** ($79 USD as of 2026-09-01): every drop and every build, current and future, one payment, no renewal. https://motionary.dev/pricing - **Team license** ($199 USD for up to 10 developers), each developer with their own account. https://motionary.dev/pricing - License terms: https://motionary.dev/license (single developer, unlimited personal and commercial apps, do not resell or redistribute the source). - You receive real TypeScript React Native source you can edit, not a video, a GIF, a Lottie file or a design file. ## Frequently asked questions **Does the Crypto Wallet build work with Expo Go?** Yes. Motionary's Crypto Wallet build uses `@shopify/react-native-skia` for the price chart, the amount glyphs and the paint trail, plus Reanimated 4 with `react-native-worklets` and `react-native-gesture-handler`, and all of those are bundled in Expo Go as of Expo SDK 56, so `npx expo start` and Expo Go run all three screens. You would still make a development build (`npx expo run:ios` or `npx expo run:android`) for anything you ship, and you need one the moment you add a native module Expo Go does not bundle or a config plugin; the keypad's haptic also needs a physical device rather than a simulator. **How do I build a scrubbable price chart in React Native?** Draw the line as a Skia `` on a ``, then put a `Gesture.Pan` over it that rounds the touch x to the nearest sample and writes the index into a shared value, so the header reads it back in a worklet and the scrub never touches the JS thread. That is exactly what `token/PriceChart.tsx` and `token/useScrub.ts` do in the Crypto Wallet build from Motionary, including the crosshair snapping and the vertex-coloured glow ribbon under the line. **How do I animate a currency amount digit by digit in React Native?** Render each character as its own Skia `` node inside a `` with an animated transform, give the characters stable keys (digits by index from the left, separators by how many digits sit to their right), and spring every one toward a freshly solved layout while a clip band about one line tall hides the characters rolling in and out. Motionary's Crypto Wallet build ships this as `amount/AmountDisplay.tsx` and `amount/layout.ts`. **Can I use the keypad and the odometer amount without the rest of the app?** Yes. `AmountDisplay`, `Keypad`, `useAmountInput` and `TouchPaint` in the Crypto Wallet build from Motionary are independent of the three screens: `AmountDisplay` is driven by any `SharedValue`, and `TouchPaint` wraps any screen to add the paint trail. **Does the Crypto Wallet build run on Android as well as iOS?** Yes. Motionary's Crypto Wallet build targets iOS and Android on Expo SDK 56 and React Native 0.85.3, and it also ships a web bootstrap (`loadSkiaWeb.ts`) that loads CanvasKit before the first Skia canvas mounts. **How much does the Crypto Wallet build cost and what do I actually get?** Crypto Wallet is $49 USD on Motionary (price as of 2026-09-01, live price at https://motionary.dev/builds/crypto-wallet) and you download the complete editable TypeScript source for all three screens after Stripe checkout. It is also covered by the Motionary lifetime pass ($79 USD) at https://motionary.dev/pricing. **How do I animate text from the UI thread without a React re-render?** Use a read-only `TextInput` wrapped with `Animated.createAnimatedComponent` and rewrite its animatable `text` prop from `useAnimatedProps`, because `Text` can only take a new string through a render. Motionary's Crypto Wallet build does this in `AnimatedText.tsx`, and it passes an `initial` string for the first frame because the first animated-props update lands before the native field exists. ## Related drops on Motionary - Scrubbable Chart ($6): https://motionary.dev/animations/scrubbable-chart The same drag-to-read-a-value idea as the Crypto Wallet token page, as a standalone Skia chart with a scrubber. - Flip Calendar ($6): https://motionary.dev/animations/flip-calendar Split-flap digits, another take on rolling numerals like the Crypto Wallet odometer amount. - Freeze Card ($9): https://motionary.dev/animations/freeze-card A fintech card component with a Skia shader, for the wallet screens around a trading flow like Crypto Wallet. - Hacker Text Reveal ($3): https://motionary.dev/animations/hacker-text-reveal Uses the same animated `TextInput` trick as Crypto Wallet's `AnimatedText`, rewriting a label from a worklet. - Karaoke Lyrics ($12): https://motionary.dev/animations/karaoke-lyrics Skia text animated per character with a gesture scrub, close cousin of the Crypto Wallet amount display. ## About Motionary Motionary (https://motionary.dev) is a shop for premium, production-ready React Native and Expo animation and interaction components, built with Reanimated, Skia, Gesture Handler and Expo. Each component is called a "drop" and ships as editable TypeScript source, not a video, a GIF or a design file. Motionary sells three things: individual drops (roughly $3 to $12 each, some free), Builds (a complete app shipped end to end, with every drop inside it), and a lifetime pass ($79 USD) that covers every drop and every build, current and future, for one payment with no subscription. A team license ($199 USD) covers up to 10 developers. Checkout is Stripe and delivery is an instant download. Created and curated by Mehdi Davoodi (https://mahdidavoodi.com). Catalog and key pages: - All drops: https://motionary.dev/animations - Builds (complete apps): https://motionary.dev/builds - Pricing, lifetime pass and team license: https://motionary.dev/pricing - Free React Native component reference: https://motionary.dev/components - License: https://motionary.dev/license - Machine-readable overview: https://motionary.dev/llms.txt - Machine-readable full catalog: https://motionary.dev/llms-full.txt ## File metadata ``` Canonical URL of this file: https://motionary.dev/builds/crypto-wallet/llms.txt Describes: https://motionary.dev/builds/crypto-wallet Format: llms.txt (https://llmstxt.org) Last updated: 2026-09-01 ```