// Finance app UI
Crypto Wallet App UI Design in Expo
This crypto wallet app UI pairs a calm violet and lemon palette with the screens a wallet needs first: onboarding, a portfolio home, and a coin detail view with a candlestick chart.
- Screens
- 3
- Built with
- Expo SDK 58
- Fonts
- IBM Plex Sans, Exo 2
- License
- Free (MIT)

Crypto Wallet app screens

Onboarding
A dark cloud illustration with floating coin marks on violet, one headline and a single Next button.

Wallet home
Current value, transfer, swap and receive actions, favourite coins with sparklines, assets and a curved tab bar.

Coin detail
A violet sheet with price, change, time range tabs, a candlestick chart with a price axis, and sell and buy buttons.
Copy the Crypto Wallet kit
Use the artifact as a design brief, the skill to generate the UI with an AI agent, or the code to run it right away.
Design artifact
The full design: tokens, screens and source
# Crypto Wallet: design artifact
This crypto wallet app UI pairs a calm violet and lemon palette with the screens a wallet needs first: onboarding, a portfolio home, and a coin detail view with a candlestick chart.
- Type: Finance mobile app UI
- Screens: 3
- Artboard: 390 × 844
- Target: Expo SDK 58, Expo Router, TypeScript, react-native-svg
- Live page: https://developermill.com/app-designs/crypto-wallet-app-ui-design
## Design direction
Deep violet and pale lemon with light Exo 2 headlines, soft pastel cards and a curved tab bar around a raised action.
- Candlestick chart drawn in plain SVG
- Sparkline favourites cards
- Curved tab bar with a raised action button
- Time range tabs and buy and sell actions
## Foundations
### Colour
| Token | Hex |
| --- | --- |
| Deep violet | `#22203A` |
| Iris | `#6E5ED0` |
| Lemon | `#F4F1A6` |
| Periwinkle | `#CBCDF8` |
| Lavender | `#DCC9F6` |
| Mist | `#F1F0F6` |
### Typography
- Typefaces: IBM Plex Sans, Exo 2
- Common sizes (px): 9, 11, 13, 14, 16, 20, 42, 44
### Shape and depth
- Common corner radii (px): 18, 20, 22, 24, 28, 32
- Shadows: None
## Screens
### 1. Onboarding
A dark cloud illustration with floating coin marks on violet, one headline and a single Next button.
Preview: https://developermill.com/app-designs/crypto-wallet-app-ui-design/onboarding.webp
Copy on this screen:
- Trusted & Secure Crypto Wallet
- Next
### 2. Wallet home
Current value, transfer, swap and receive actions, favourite coins with sparklines, assets and a curved tab bar.
Preview: https://developermill.com/app-designs/crypto-wallet-app-ui-design/wallet.webp
Copy on this screen:
- VISA
- Current value
- $30,540
- .00
- Transfer
- Receive
- Favourites
- $1467.64
- ↗ +9.0%
- Ripple
- XRP
- $195.00
- ↗ +1.4%
- Ethereum
- ETH
- Assets
- ₿
- Bitcoin
- BTC
- $10,265.016
- +12.32%
### 3. Coin detail
A violet sheet with price, change, time range tabs, a candlestick chart with a price axis, and sell and buy buttons.
Preview: https://developermill.com/app-designs/crypto-wallet-app-ui-design/detail.webp
Copy on this screen:
- Bitcoin
- ₿
- BTC
- 7154.45
- ↘ 245.22 (5.58%)
- 1D
- 7D
- 1M
- 6M
- 1Y
- $1800
- $1728
- $1700
- $1600
- $1500
- $1400
- $1300
- SUN
- MON
- TUE
- WED
- THU
- FRI
- SAT
- Sell
- Buy
## Full source
The complete design source for each screen. Images point at hosted demo files.
### Main
```html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Onboarding</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;500;600&family=Exo+2:wght@200;300;400&display=swap">
<style>
body{margin:0}
a{color:#F4F1A6}a:hover{color:#ffffff}
</style>
</helmet>
<div style="width: 390px; height: 844px; box-sizing: border-box; background: {{accent}}; position: relative; overflow: hidden; font-family: 'IBM Plex Sans', system-ui, sans-serif; color: #FFFFFF">
<svg width="390" height="520" viewBox="0 0 390 520" aria-hidden="true" style="position: absolute; top: 0; left: 0">
<g fill="#22203A">
<circle cx="150" cy="210" r="74"></circle>
<circle cx="70" cy="300" r="78"></circle>
<circle cx="190" cy="330" r="96"></circle>
<circle cx="300" cy="300" r="70"></circle>
<circle cx="250" cy="200" r="48"></circle>
<circle cx="350" cy="230" r="38"></circle>
<circle cx="40" cy="380" r="56"></circle>
<circle cx="330" cy="370" r="58"></circle>
<circle cx="120" cy="410" r="60"></circle>
<circle cx="250" cy="420" r="56"></circle>
</g>
<circle cx="250" cy="215" r="58" fill="#3A3854" opacity="0.9"></circle>
<circle cx="238" cy="198" r="22" fill="#5A5878" opacity="0.6"></circle>
<circle cx="40" cy="320" r="70" fill="none" stroke="#F4F1A6" stroke-width="2"></circle>
<circle cx="280" cy="370" r="46" fill="none" stroke="#FFFFFF" stroke-width="1.5" opacity="0.85"></circle>
<circle cx="250" cy="390" r="28" fill="none" stroke="#FFFFFF" stroke-width="1.5" opacity="0.85"></circle>
<circle cx="372" cy="255" r="14" fill="none" stroke="#F4F1A6" stroke-width="2"></circle>
<circle cx="440" cy="40" r="330" fill="none" stroke="#FFFFFF" stroke-width="1" opacity="0.18"></circle>
<circle cx="310" cy="95" r="40" fill="#FFFFFF" fill-opacity="0.12" stroke="#FFFFFF" stroke-opacity="0.45"></circle>
<text x="310" y="108" transform="rotate(-15 310 95)" text-anchor="middle" font-family="IBM Plex Sans, sans-serif" font-size="36" font-weight="500" fill="#FFFFFF">$</text>
<circle cx="130" cy="150" r="32" fill="#FFFFFF" fill-opacity="0.12" stroke="#FFFFFF" stroke-opacity="0.45"></circle>
<text x="130" y="160" text-anchor="middle" font-family="IBM Plex Sans, sans-serif" font-size="26" font-weight="600" fill="#FFFFFF">₿</text>
</svg>
<div style="position: absolute; left: 40px; right: 40px; bottom: 96px; display: flex; flex-direction: column; gap: 56px">
<h1 style="margin: 0; font-family: 'Exo 2', sans-serif; font-size: 42px; line-height: 1.1; font-weight: 300; letter-spacing: 0.3px">Trusted & Secure Crypto Wallet</h1>
<button type="button" style="align-self: center; width: 200px; height: 56px; border: 0; border-radius: 28px; background: #F4F1A6; color: #22203A; font-family: 'IBM Plex Sans', sans-serif; font-size: 16px; font-weight: 500; cursor: pointer">Next</button>
</div>
<div style="position: absolute; left: 50%; bottom: 72px; width: 24px; height: 3px; margin-left: -12px; border-radius: 2px; background: #22203A"></div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"accent":{"editor":"color","default":"#6E5ED0","options":["#6E5ED0","#5B4BC4","#2F6BD8","#22203A"]},"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
return { accent: this.props.accent ?? '#6E5ED0' };
}
}
</script>
</body>
</html>
```
### Wallet
```html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Wallet home</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;500;600&family=Exo+2:wght@200;300;400&display=swap">
<style>
body{margin:0}
a{color:#5B4BC4}a:hover{color:#22203A}
</style>
</helmet>
<div style="width: 390px; height: 844px; box-sizing: border-box; background: #FFFFFF; position: relative; overflow: hidden; font-family: 'IBM Plex Sans', system-ui, sans-serif; color: #22203A">
<div style="padding: 56px 24px 0; display: flex; flex-direction: column; gap: 0">
<div style="display: flex; align-items: center; justify-content: space-between">
<svg width="22" height="22" viewBox="0 0 22 22" role="img" aria-label="Wallet logo"><circle cx="6" cy="6" r="3.5" fill="none" stroke="#22203A" stroke-width="1.6"></circle><circle cx="16" cy="6" r="3.5" fill="none" stroke="#22203A" stroke-width="1.6"></circle><circle cx="6" cy="16" r="3.5" fill="none" stroke="#22203A" stroke-width="1.6"></circle></svg>
<div style="display: flex; align-items: center; gap: 12px">
<button type="button" aria-label="Add card" style="width: 44px; height: 44px; border: 0; border-radius: 22px; background: #F1F0F6; display: flex; align-items: center; justify-content: center; cursor: pointer"><svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><path d="M8 2v12M2 8h12" stroke="#22203A" stroke-width="1.8" stroke-linecap="round"></path></svg></button>
<button type="button" aria-label="Linked cards" style="height: 44px; padding: 0 6px 0 14px; border: 0; border-radius: 22px; background: #22203A; display: flex; align-items: center; gap: 8px; cursor: pointer">
<span style="color: #FFFFFF; font-family: 'IBM Plex Sans', sans-serif; font-size: 11px; font-weight: 600; font-style: italic">VISA</span>
<span style="width: 32px; height: 32px; border-radius: 16px; background: #FFFFFF; display: flex; align-items: center; justify-content: center"><svg width="22" height="14" viewBox="0 0 22 14" aria-hidden="true"><circle cx="7" cy="7" r="6" fill="#22203A"></circle><circle cx="15" cy="7" r="6" fill="none" stroke="#22203A" stroke-width="1.6"></circle></svg></span>
</button>
</div>
</div>
<p style="margin: 32px 0 6px; font-size: 14px; color: #6B6880">Current value</p>
<p style="margin: 0; font-size: 44px; font-weight: 400; letter-spacing: -1px">$30,540<span style="color: #8E8BA0">.00</span></p>
<div style="margin-top: 20px; display: flex; align-items: center; gap: 10px">
<button type="button" style="flex: 1; height: 48px; border: 0; border-radius: 24px; background: #F1F0F6; display: flex; align-items: center; gap: 12px; padding: 0 6px; font-family: 'IBM Plex Sans', sans-serif; font-size: 13px; color: #22203A; cursor: pointer"><span style="width: 36px; height: 36px; border-radius: 18px; background: #D9D4F7; display: flex; align-items: center; justify-content: center"><svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true"><path d="M7 11V3M3.5 6.5 7 3l3.5 3.5M2 13h10" fill="none" stroke="#22203A" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"></path></svg></span>Transfer</button>
<button type="button" aria-label="Swap" style="width: 44px; height: 44px; flex: none; border: 0; border-radius: 22px; background: #D9D4F7; display: flex; align-items: center; justify-content: center; cursor: pointer"><svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><path d="M2 4h3l6 8h3M2 12h3l2-2.7M9 6.7 11 4h3M12 2l2 2-2 2M12 10l2 2-2 2" fill="none" stroke="#22203A" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg></button>
<button type="button" style="flex: 1; height: 48px; border: 0; border-radius: 24px; background: #F1F0F6; display: flex; align-items: center; justify-content: space-between; padding: 0 6px 0 20px; font-family: 'IBM Plex Sans', sans-serif; font-size: 13px; color: #22203A; cursor: pointer">Receive<span style="width: 36px; height: 36px; border-radius: 18px; background: #D9D4F7; display: flex; align-items: center; justify-content: center"><svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true"><path d="M7 1v8M3.5 5.5 7 9l3.5-3.5M2 13h10" fill="none" stroke="#22203A" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"></path></svg></span></button>
</div>
<p style="margin: 28px 0 12px; font-size: 14px; color: #6B6880">Favourites</p>
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px">
<div style="background: #F4F1A6; border-radius: 28px; padding: 20px 16px 16px; display: flex; flex-direction: column; gap: 6px">
<p style="margin: 0; font-size: 20px; font-weight: 500; text-align: center">$1467.64</p>
<p style="margin: 0; font-size: 11px; text-align: center; color: #3B3852">↗ +9.0%</p>
<svg width="100%" height="56" viewBox="0 0 140 56" preserveAspectRatio="none" aria-hidden="true"><polyline points="0,44 14,40 26,46 40,36 52,40 66,30 78,34 92,22 104,26 118,12 130,16 140,6" fill="none" stroke="#22203A" stroke-width="1.6" stroke-linejoin="round"></polyline></svg>
<div style="display: flex; align-items: center; gap: 10px">
<span style="width: 40px; height: 40px; border-radius: 20px; background: #FFFFFF; display: flex; align-items: center; justify-content: center"><svg width="18" height="18" viewBox="0 0 18 18" aria-hidden="true"><path d="M3 4c2 2 3.5 3 6 3s4-1 6-3M3 14c2-2 3.5-3 6-3s4 1 6 3" fill="none" stroke="#22203A" stroke-width="1.6" stroke-linecap="round"></path></svg></span>
<div><p style="margin: 0; font-size: 14px; font-weight: 500">Ripple</p><p style="margin: 0; font-size: 11px; color: #4D4A63">XRP</p></div>
</div>
</div>
<div style="background: #DCC9F6; border-radius: 28px; padding: 20px 16px 16px; display: flex; flex-direction: column; gap: 6px">
<p style="margin: 0; font-size: 20px; font-weight: 500; text-align: center">$195.00</p>
<p style="margin: 0; font-size: 11px; text-align: center; color: #3B3852">↗ +1.4%</p>
<svg width="100%" height="56" viewBox="0 0 140 56" preserveAspectRatio="none" aria-hidden="true"><polyline points="0,40 12,30 22,36 34,26 46,34 58,24 68,30 80,20 92,32 104,22 116,28 128,14 140,20" fill="none" stroke="#22203A" stroke-width="1.6" stroke-linejoin="round"></polyline></svg>
<div style="display: flex; align-items: center; gap: 10px">
<span style="width: 40px; height: 40px; border-radius: 20px; background: #FFFFFF; display: flex; align-items: center; justify-content: center"><svg width="14" height="20" viewBox="0 0 14 20" aria-hidden="true"><path d="M7 1 1 10l6 3.5 6-3.5L7 1ZM1 11.5 7 19l6-7.5-6 3.5-6-3.5Z" fill="#22203A"></path></svg></span>
<div><p style="margin: 0; font-size: 14px; font-weight: 500">Ethereum</p><p style="margin: 0; font-size: 11px; color: #4D4A63">ETH</p></div>
</div>
</div>
</div>
<p style="margin: 26px 0 12px; font-size: 14px; color: #6B6880">Assets</p>
<div style="background: #F1F0F6; border-radius: 22px; padding: 14px 18px 14px 14px; display: flex; align-items: center; gap: 14px">
<span style="width: 40px; height: 40px; border-radius: 20px; background: #FFFFFF; display: flex; align-items: center; justify-content: center; font-size: 18px; font-weight: 600">₿</span>
<div style="flex: 1"><p style="margin: 0; font-size: 14px; font-weight: 500">Bitcoin</p><p style="margin: 0; font-size: 11px; color: #6B6880">BTC</p></div>
<div style="text-align: right"><p style="margin: 0; font-size: 14px; font-weight: 500">$10,265.016</p><p style="margin: 0; font-size: 11px; color: #4D4A63">+12.32%</p></div>
</div>
</div>
<nav aria-label="Main" style="position: absolute; left: 0; right: 0; bottom: 0; height: 100px">
<svg width="390" height="100" viewBox="0 0 390 100" aria-hidden="true" style="position: absolute; left: 0; bottom: 0"><path d="M0 18 C30 10 60 5 95 4 C118 3 130 5 138 9 C144 12 148 16 148 21 A47 47 0 0 0 242 21 C242 16 246 12 252 9 C260 5 272 3 290 3 C325 4 360 12 390 21 L390 100 L0 100 Z" fill="#22203A"></path></svg>
<button type="button" aria-label="New transaction" style="position: absolute; left: 160px; top: -14px; width: 70px; height: 70px; border-radius: 35px; border: 0; background: #D2D6FA; display: flex; align-items: center; justify-content: center; cursor: pointer"><svg width="22" height="22" viewBox="0 0 22 22" aria-hidden="true"><path d="M11 2v18M2 11h18" stroke="#22203A" stroke-width="1.6" stroke-linecap="round"></path></svg></button>
<button type="button" aria-label="Home" style="position: absolute; left: 24px; top: 26px; width: 48px; height: 48px; border: 0; background: transparent; display: flex; align-items: center; justify-content: center; cursor: pointer"><svg width="24" height="24" viewBox="0 0 24 24" aria-hidden="true"><path d="M4 10.2c0-.6.3-1.2.8-1.6l6-4.6c.7-.5 1.7-.5 2.4 0l6 4.6c.5.4.8 1 .8 1.6V19c0 1.1-.9 2-2 2H6c-1.1 0-2-.9-2-2Z" fill="#FFFFFF"></path></svg></button>
<button type="button" aria-label="Markets" style="position: absolute; left: 84px; top: 26px; width: 48px; height: 48px; border: 0; background: transparent; display: flex; align-items: center; justify-content: center; cursor: pointer"><svg width="24" height="24" viewBox="0 0 24 24" aria-hidden="true"><g fill="none" stroke="#FFFFFF" stroke-width="1.6"><rect x="2.5" y="15" width="5" height="6" rx="2.5"></rect><rect x="9.5" y="10" width="5" height="11" rx="2.5"></rect><rect x="16.5" y="5" width="5" height="16" rx="2.5"></rect></g></svg></button>
<button type="button" aria-label="Wallets" style="position: absolute; left: 260px; top: 26px; width: 48px; height: 48px; border: 0; background: transparent; display: flex; align-items: center; justify-content: center; cursor: pointer"><svg width="24" height="24" viewBox="0 0 24 24" aria-hidden="true"><g fill="none" stroke="#FFFFFF" stroke-width="1.6"><circle cx="12" cy="12" r="9"></circle><path d="M21 9.5h-4.5a2.5 2.5 0 0 0 0 5H21"></path></g></svg></button>
<button type="button" aria-label="Profile" style="position: absolute; left: 316px; top: 26px; width: 48px; height: 48px; border: 0; background: transparent; display: flex; align-items: center; justify-content: center; cursor: pointer"><svg width="24" height="24" viewBox="0 0 24 24" aria-hidden="true"><g fill="none" stroke="#FFFFFF" stroke-width="1.6"><circle cx="12" cy="7.5" r="4"></circle><rect x="4.5" y="14" width="15" height="7" rx="3.5"></rect></g></svg></button>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
return {};
}
}
</script>
</body>
</html>
```
### Detail
```html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Coin detail</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;500;600&family=Exo+2:wght@200;300;400&display=swap">
<style>
body{margin:0}
a{color:#5B4BC4}a:hover{color:#22203A}
</style>
</helmet>
<div style="width: 390px; height: 844px; box-sizing: border-box; background: #6E5ED0; position: relative; overflow: hidden; font-family: 'IBM Plex Sans', system-ui, sans-serif; color: #22203A">
<div style="position: absolute; left: 0; right: 0; top: 40px; bottom: 0; background: #CBCDF8; border-radius: 32px 32px 0 0; padding: 20px 24px 0; display: flex; flex-direction: column">
<div style="display: flex; align-items: center; justify-content: space-between">
<button type="button" style="height: 44px; border: 0; background: transparent; padding: 0; display: flex; align-items: center; gap: 8px; font-family: 'IBM Plex Sans', sans-serif; font-size: 15px; font-weight: 600; color: #22203A; cursor: pointer">Bitcoin<svg width="10" height="6" viewBox="0 0 10 6" aria-hidden="true"><path d="M0 0h10L5 6Z" fill="#22203A"></path></svg></button>
<button type="button" aria-label="Close" style="width: 44px; height: 44px; border: 0; background: transparent; display: flex; align-items: center; justify-content: center; cursor: pointer"><svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><path d="M2 2l12 12M14 2 2 14" stroke="#22203A" stroke-width="1.8" stroke-linecap="round"></path></svg></button>
</div>
<div style="display: flex; flex-direction: column; align-items: center; margin-top: 8px">
<span style="width: 52px; height: 52px; border-radius: 26px; background: #F4F1A6; display: flex; align-items: center; justify-content: center; font-size: 22px; font-weight: 600">₿</span>
<p style="margin: 8px 0 0; font-size: 11px; color: #4D4A63">BTC</p>
<p style="margin: 14px 0 0; font-size: 46px; font-weight: 400; letter-spacing: -1px">7154.45</p>
<p style="margin: 6px 0 0; font-size: 13px; color: #3B3852">↘ 245.22 (5.58%)</p>
</div>
<div role="tablist" aria-label="Time range" style="margin-top: 26px; display: flex; justify-content: space-between; padding: 0 8px">
<button type="button" role="tab" aria-selected="false" style="width: 48px; height: 44px; border: 0; border-radius: 22px; background: transparent; font-family: 'IBM Plex Sans', sans-serif; font-size: 13px; color: #3B3852; cursor: pointer">1D</button>
<button type="button" role="tab" aria-selected="true" style="width: 48px; height: 44px; border: 0; border-radius: 22px; background: #22203A; font-family: 'IBM Plex Sans', sans-serif; font-size: 13px; color: #FFFFFF; cursor: pointer">7D</button>
<button type="button" role="tab" aria-selected="false" style="width: 48px; height: 44px; border: 0; border-radius: 22px; background: transparent; font-family: 'IBM Plex Sans', sans-serif; font-size: 13px; color: #3B3852; cursor: pointer">1M</button>
<button type="button" role="tab" aria-selected="false" style="width: 48px; height: 44px; border: 0; border-radius: 22px; background: transparent; font-family: 'IBM Plex Sans', sans-serif; font-size: 13px; color: #3B3852; cursor: pointer">6M</button>
<button type="button" role="tab" aria-selected="false" style="width: 48px; height: 44px; border: 0; border-radius: 22px; background: transparent; font-family: 'IBM Plex Sans', sans-serif; font-size: 13px; color: #3B3852; cursor: pointer">1Y</button>
</div>
<div style="margin-top: 22px; display: flex; gap: 10px">
<svg width="290" height="200" viewBox="0 -10 290 180" role="img" aria-label="Bitcoin 7-day candlestick chart, ranging from about 1440 to 1750 dollars">
<g stroke="#A9AADE" stroke-width="1">
<line x1="0" y1="0" x2="290" y2="0"></line><line x1="0" y1="32" x2="290" y2="32"></line><line x1="0" y1="64" x2="290" y2="64"></line><line x1="0" y1="96" x2="290" y2="96"></line><line x1="0" y1="128" x2="290" y2="128"></line><line x1="0" y1="160" x2="290" y2="160"></line>
</g>
<line x1="0" y1="23" x2="290" y2="23" stroke="#22203A" stroke-width="1" stroke-dasharray="3 3"></line>
<g stroke-width="1.5" stroke-linecap="round">
<line x1="10" y1="51.2" x2="10" y2="76.8" stroke="#5B4BC4"></line><rect x="6.5" y="57.6" width="7" height="12.8" rx="2" fill="#5B4BC4"></rect>
<line x1="30" y1="35.2" x2="30" y2="70.4" stroke="#5B4BC4"></line><rect x="26.5" y="41.6" width="7" height="22.4" rx="2" fill="#5B4BC4"></rect>
<line x1="50" y1="44.8" x2="50" y2="83.2" stroke="#F2EE8E"></line><rect x="46.5" y="51.2" width="7" height="22.4" rx="2" fill="#F2EE8E"></rect>
<line x1="70" y1="57.6" x2="70" y2="96" stroke="#5B4BC4"></line><rect x="66.5" y="64" width="7" height="25.6" rx="2" fill="#5B4BC4"></rect>
<line x1="90" y1="38.4" x2="90" y2="76.8" stroke="#F2EE8E"></line><rect x="86.5" y="48" width="7" height="19.2" rx="2" fill="#F2EE8E"></rect>
<line x1="110" y1="48" x2="110" y2="112" stroke="#5B4BC4"></line><rect x="106.5" y="64" width="7" height="38.4" rx="2" fill="#5B4BC4"></rect>
<line x1="130" y1="32" x2="130" y2="70.4" stroke="#F2EE8E"></line><rect x="126.5" y="38.4" width="7" height="22.4" rx="2" fill="#F2EE8E"></rect>
<line x1="150" y1="16" x2="150" y2="89.6" stroke="#5B4BC4"></line><rect x="146.5" y="35.2" width="7" height="41.6" rx="2" fill="#5B4BC4"></rect>
<line x1="170" y1="41.6" x2="170" y2="102.4" stroke="#5B4BC4"></line><rect x="166.5" y="51.2" width="7" height="38.4" rx="2" fill="#5B4BC4"></rect>
<line x1="190" y1="28.8" x2="190" y2="64" stroke="#F2EE8E"></line><rect x="186.5" y="35.2" width="7" height="19.2" rx="2" fill="#F2EE8E"></rect>
<line x1="210" y1="44.8" x2="210" y2="115.2" stroke="#5B4BC4"></line><rect x="206.5" y="57.6" width="7" height="44.8" rx="2" fill="#5B4BC4"></rect>
<line x1="230" y1="51.2" x2="230" y2="96" stroke="#F2EE8E"></line><rect x="226.5" y="60.8" width="7" height="25.6" rx="2" fill="#F2EE8E"></rect>
<line x1="250" y1="35.2" x2="250" y2="76.8" stroke="#5B4BC4"></line><rect x="246.5" y="44.8" width="7" height="22.4" rx="2" fill="#5B4BC4"></rect>
<line x1="270" y1="32" x2="270" y2="64" stroke="#F2EE8E"></line><rect x="266.5" y="38.4" width="7" height="22.4" rx="2" fill="#F2EE8E"></rect>
</g>
</svg>
<div style="position: relative; width: 42px; height: 200px; font-size: 9px; color: #4D4A63">
<span style="position: absolute; top: 4px">$1800</span>
<span style="position: absolute; top: 18px; left: -4px; padding: 3px 6px; border-radius: 8px; background: #22203A; color: #FFFFFF">$1728</span>
<span style="position: absolute; top: 44px">$1700</span>
<span style="position: absolute; top: 79px">$1600</span>
<span style="position: absolute; top: 115px">$1500</span>
<span style="position: absolute; top: 150px">$1400</span>
<span style="position: absolute; top: 186px">$1300</span>
</div>
</div>
<div style="margin-top: 8px; width: 290px; display: flex; justify-content: space-between; font-size: 9px; color: #4D4A63">
<span>SUN</span><span>MON</span><span>TUE</span><span>WED</span><span>THU</span><span>FRI</span><span>SAT</span>
</div>
<div style="position: absolute; left: 24px; right: 24px; bottom: 44px; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px">
<button type="button" style="height: 64px; border: 0; border-radius: 32px; background: #F4F1A6; font-family: 'IBM Plex Sans', sans-serif; font-size: 16px; font-weight: 500; color: #22203A; cursor: pointer">Sell</button>
<button type="button" style="height: 64px; border: 0; border-radius: 32px; background: #22203A; font-family: 'IBM Plex Sans', sans-serif; font-size: 16px; font-weight: 500; color: #FFFFFF; cursor: pointer">Buy</button>
</div>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
return {};
}
}
</script>
</body>
</html>
```SKILL.md
Save as .claude/skills/crypto-wallet-app-ui/SKILL.md
--- name: crypto-wallet-app-ui description: Build the Crypto Wallet mobile app UI in Expo React Native. Use when asked to create a crypto wallet app UI or a new screen in this visual style. --- # Crypto Wallet app UI Build this UI in an Expo SDK 58 app with Expo Router and strict TypeScript. Match the spec below rather than inventing a new look. The finished reference lives at https://developermill.com/app-designs/crypto-wallet-app-ui-design ## Visual direction Deep violet and pale lemon with light Exo 2 headlines, soft pastel cards and a curved tab bar around a raised action. Keep these signature details: - Candlestick chart drawn in plain SVG - Sparkline favourites cards - Curved tab bar with a raised action button - Time range tabs and buy and sell actions ## Set up ```bash npx expo install react-native-svg @expo-google-fonts/exo-2 @expo-google-fonts/ibm-plex-sans expo-font ``` ## Tokens | Token | Hex | | --- | --- | | Deep violet | `#22203A` | | Iris | `#6E5ED0` | | Lemon | `#F4F1A6` | | Periwinkle | `#CBCDF8` | | Lavender | `#DCC9F6` | | Mist | `#F1F0F6` | - Typefaces: IBM Plex Sans, Exo 2 - Common sizes (px): 9, 11, 13, 14, 16, 20, 42, 44 - Common corner radii (px): 18, 20, 22, 24, 28, 32 Define these once and reuse them. Do not add new colours. ## Screens Build one Expo Router route per screen, in this order: 1. **Onboarding**: A dark cloud illustration with floating coin marks on violet, one headline and a single Next button. 2. **Wallet home**: Current value, transfer, swap and receive actions, favourite coins with sparklines, assets and a curved tab bar. 3. **Coin detail**: A violet sheet with price, change, time range tabs, a candlestick chart with a price axis, and sell and buy buttons. ## Build rules - Design on a 390 × 844 artboard, then scale to the device width so layouts match on every phone. - Load each custom font weight by its own family name with expo-font. Do not rely on `fontWeight` with custom fonts. - Draw icons, charts and illustrations with react-native-svg rather than image files or chart libraries. - Use `Pressable` with an `accessibilityLabel` for every icon-only control, and keep touch targets at 44 px or larger. - Wire navigation with `router.navigate`, and keep sample data in constants at the top of each file so it is easy to replace. - Use expo-image for photos, with `contentFit` set explicitly. ## Done when - Every screen above exists as a route and they link together. - Colours, type and radii match the tokens exactly. - `npx tsc --noEmit` and `npx expo lint` both pass. - Layouts hold up on small and large phones.
Set up the project
npx create-expo-app@latest crypto-wallet-app --template default cd crypto-wallet-app rm -rf src npx expo install react-native-svg @expo-google-fonts/exo-2 @expo-google-fonts/ibm-plex-sans expo-font
src/app/_layout.tsx
import { Exo2_300Light } from '@expo-google-fonts/exo-2';
import {
IBMPlexSans_400Regular,
IBMPlexSans_500Medium,
IBMPlexSans_600SemiBold,
} from '@expo-google-fonts/ibm-plex-sans';
import { useFonts } from 'expo-font';
import { Stack } from 'expo-router';
export default function RootLayout() {
const [fontsLoaded] = useFonts({
Exo2_300Light,
IBMPlexSans_400Regular,
IBMPlexSans_500Medium,
IBMPlexSans_600SemiBold,
});
if (!fontsLoaded) return null;
return <Stack screenOptions={{ headerShown: false }} />;
}src/app/detail.tsx
import { Pressable, Text, View } from 'react-native';
import Svg, { G, Line, Path, Rect } from 'react-native-svg';
import { Screen } from '@/components/screen';
export default function DetailScreen() {
return (
<Screen background="#6E5ED0" statusBar="light">
<View style={{ flex: 1 }}>
<View
style={{
position: 'absolute',
left: 0,
right: 0,
top: 40,
bottom: 0,
backgroundColor: '#CBCDF8',
borderTopLeftRadius: 32,
borderTopRightRadius: 32,
borderBottomRightRadius: 0,
borderBottomLeftRadius: 0,
paddingTop: 20,
paddingBottom: 0,
paddingHorizontal: 24,
}}>
<View
style={{ alignItems: 'center', justifyContent: 'space-between', flexDirection: 'row' }}>
<Pressable
accessibilityRole="button"
style={{
height: 44,
borderWidth: 0,
padding: 0,
alignItems: 'center',
gap: 8,
flexShrink: 1,
flexDirection: 'row',
}}>
<Text
style={{
fontFamily: 'IBMPlexSans_600SemiBold',
fontSize: 15,
color: '#22203A',
flexShrink: 1,
}}>
Bitcoin
</Text>
<Svg width="10" height="6" viewBox="0 0 10 6">
<Path d="M0 0h10L5 6Z" fill="#22203A" />
</Svg>
</Pressable>
<Pressable
accessibilityRole="button"
accessibilityLabel="Close"
style={{
width: 44,
height: 44,
borderWidth: 0,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg width="16" height="16" viewBox="0 0 16 16">
<Path
d="M2 2l12 12M14 2 2 14"
stroke="#22203A"
strokeWidth="1.8"
strokeLinecap="round"
/>
</Svg>
</Pressable>
</View>
<View style={{ alignItems: 'center', marginTop: 8 }}>
<View
style={{
width: 52,
height: 52,
borderRadius: 26,
backgroundColor: '#F4F1A6',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Text
style={{
fontFamily: 'IBMPlexSans_600SemiBold',
fontSize: 22,
color: '#22203A',
flexShrink: 1,
}}>
₿
</Text>
</View>
<Text
style={{
marginTop: 8,
marginBottom: 0,
marginHorizontal: 0,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 11,
color: '#4D4A63',
}}>
BTC
</Text>
<Text
style={{
marginTop: 14,
marginBottom: 0,
marginHorizontal: 0,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 46,
color: '#22203A',
letterSpacing: -1,
}}>
7154.45
</Text>
<Text
style={{
marginTop: 6,
marginBottom: 0,
marginHorizontal: 0,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 13,
color: '#3B3852',
}}>
↘ 245.22 (5.58%)
</Text>
</View>
<View
style={{
marginTop: 26,
justifyContent: 'space-between',
paddingVertical: 0,
paddingHorizontal: 8,
flexDirection: 'row',
}}>
<Pressable
accessibilityRole="button"
style={{
width: 48,
height: 44,
borderWidth: 0,
borderRadius: 22,
alignItems: 'center',
justifyContent: 'center',
}}>
<Text
style={{
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 13,
color: '#3B3852',
textAlign: 'center',
}}>
1D
</Text>
</Pressable>
<Pressable
accessibilityRole="button"
style={{
width: 48,
height: 44,
borderWidth: 0,
borderRadius: 22,
backgroundColor: '#22203A',
alignItems: 'center',
justifyContent: 'center',
}}>
<Text
style={{
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 13,
color: '#FFFFFF',
textAlign: 'center',
}}>
7D
</Text>
</Pressable>
<Pressable
accessibilityRole="button"
style={{
width: 48,
height: 44,
borderWidth: 0,
borderRadius: 22,
alignItems: 'center',
justifyContent: 'center',
}}>
<Text
style={{
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 13,
color: '#3B3852',
textAlign: 'center',
}}>
1M
</Text>
</Pressable>
<Pressable
accessibilityRole="button"
style={{
width: 48,
height: 44,
borderWidth: 0,
borderRadius: 22,
alignItems: 'center',
justifyContent: 'center',
}}>
<Text
style={{
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 13,
color: '#3B3852',
textAlign: 'center',
}}>
6M
</Text>
</Pressable>
<Pressable
accessibilityRole="button"
style={{
width: 48,
height: 44,
borderWidth: 0,
borderRadius: 22,
alignItems: 'center',
justifyContent: 'center',
}}>
<Text
style={{
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 13,
color: '#3B3852',
textAlign: 'center',
}}>
1Y
</Text>
</Pressable>
</View>
<View style={{ marginTop: 22, gap: 10, flexDirection: 'row' }}>
<Svg
width="290"
height="200"
viewBox="0 -10 290 180"
accessibilityRole="image"
accessibilityLabel="Bitcoin 7-day candlestick chart, ranging from about 1440 to 1750 dollars">
<G stroke="#A9AADE" strokeWidth="1">
<Line x1="0" y1="0" x2="290" y2="0" />
<Line x1="0" y1="32" x2="290" y2="32" />
<Line x1="0" y1="64" x2="290" y2="64" />
<Line x1="0" y1="96" x2="290" y2="96" />
<Line x1="0" y1="128" x2="290" y2="128" />
<Line x1="0" y1="160" x2="290" y2="160" />
</G>
<Line
x1="0"
y1="23"
x2="290"
y2="23"
stroke="#22203A"
strokeWidth="1"
strokeDasharray="3 3"
/>
<G strokeWidth="1.5" strokeLinecap="round">
<Line x1="10" y1="51.2" x2="10" y2="76.8" stroke="#5B4BC4" />
<Rect x="6.5" y="57.6" width="7" height="12.8" rx="2" fill="#5B4BC4" />
<Line x1="30" y1="35.2" x2="30" y2="70.4" stroke="#5B4BC4" />
<Rect x="26.5" y="41.6" width="7" height="22.4" rx="2" fill="#5B4BC4" />
<Line x1="50" y1="44.8" x2="50" y2="83.2" stroke="#F2EE8E" />
<Rect x="46.5" y="51.2" width="7" height="22.4" rx="2" fill="#F2EE8E" />
<Line x1="70" y1="57.6" x2="70" y2="96" stroke="#5B4BC4" />
<Rect x="66.5" y="64" width="7" height="25.6" rx="2" fill="#5B4BC4" />
<Line x1="90" y1="38.4" x2="90" y2="76.8" stroke="#F2EE8E" />
<Rect x="86.5" y="48" width="7" height="19.2" rx="2" fill="#F2EE8E" />
<Line x1="110" y1="48" x2="110" y2="112" stroke="#5B4BC4" />
<Rect x="106.5" y="64" width="7" height="38.4" rx="2" fill="#5B4BC4" />
<Line x1="130" y1="32" x2="130" y2="70.4" stroke="#F2EE8E" />
<Rect x="126.5" y="38.4" width="7" height="22.4" rx="2" fill="#F2EE8E" />
<Line x1="150" y1="16" x2="150" y2="89.6" stroke="#5B4BC4" />
<Rect x="146.5" y="35.2" width="7" height="41.6" rx="2" fill="#5B4BC4" />
<Line x1="170" y1="41.6" x2="170" y2="102.4" stroke="#5B4BC4" />
<Rect x="166.5" y="51.2" width="7" height="38.4" rx="2" fill="#5B4BC4" />
<Line x1="190" y1="28.8" x2="190" y2="64" stroke="#F2EE8E" />
<Rect x="186.5" y="35.2" width="7" height="19.2" rx="2" fill="#F2EE8E" />
<Line x1="210" y1="44.8" x2="210" y2="115.2" stroke="#5B4BC4" />
<Rect x="206.5" y="57.6" width="7" height="44.8" rx="2" fill="#5B4BC4" />
<Line x1="230" y1="51.2" x2="230" y2="96" stroke="#F2EE8E" />
<Rect x="226.5" y="60.8" width="7" height="25.6" rx="2" fill="#F2EE8E" />
<Line x1="250" y1="35.2" x2="250" y2="76.8" stroke="#5B4BC4" />
<Rect x="246.5" y="44.8" width="7" height="22.4" rx="2" fill="#5B4BC4" />
<Line x1="270" y1="32" x2="270" y2="64" stroke="#F2EE8E" />
<Rect x="266.5" y="38.4" width="7" height="22.4" rx="2" fill="#F2EE8E" />
</G>
</Svg>
<View style={{ width: 42, height: 200 }}>
<Text
style={{
position: 'absolute',
top: 4,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 9,
color: '#4D4A63',
}}>
$1800
</Text>
<Text
style={{
position: 'absolute',
top: 18,
left: -4,
paddingVertical: 3,
paddingHorizontal: 6,
borderRadius: 8,
backgroundColor: '#22203A',
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 9,
color: '#FFFFFF',
}}>
$1728
</Text>
<Text
style={{
position: 'absolute',
top: 44,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 9,
color: '#4D4A63',
}}>
$1700
</Text>
<Text
style={{
position: 'absolute',
top: 79,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 9,
color: '#4D4A63',
}}>
$1600
</Text>
<Text
style={{
position: 'absolute',
top: 115,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 9,
color: '#4D4A63',
}}>
$1500
</Text>
<Text
style={{
position: 'absolute',
top: 150,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 9,
color: '#4D4A63',
}}>
$1400
</Text>
<Text
style={{
position: 'absolute',
top: 186,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 9,
color: '#4D4A63',
}}>
$1300
</Text>
</View>
</View>
<View
style={{
marginTop: 8,
width: 290,
justifyContent: 'space-between',
flexDirection: 'row',
}}>
<Text
style={{
flexShrink: 1,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 9,
color: '#4D4A63',
}}>
SUN
</Text>
<Text
style={{
flexShrink: 1,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 9,
color: '#4D4A63',
}}>
MON
</Text>
<Text
style={{
flexShrink: 1,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 9,
color: '#4D4A63',
}}>
TUE
</Text>
<Text
style={{
flexShrink: 1,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 9,
color: '#4D4A63',
}}>
WED
</Text>
<Text
style={{
flexShrink: 1,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 9,
color: '#4D4A63',
}}>
THU
</Text>
<Text
style={{
flexShrink: 1,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 9,
color: '#4D4A63',
}}>
FRI
</Text>
<Text
style={{
flexShrink: 1,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 9,
color: '#4D4A63',
}}>
SAT
</Text>
</View>
<View
style={{
position: 'absolute',
left: 24,
right: 24,
bottom: 44,
flexDirection: 'row',
gap: 12,
}}>
<Pressable
accessibilityRole="button"
style={{
height: 64,
borderWidth: 0,
borderRadius: 32,
backgroundColor: '#F4F1A6',
flex: 1,
alignItems: 'center',
justifyContent: 'center',
}}>
<Text
style={{
fontFamily: 'IBMPlexSans_500Medium',
fontSize: 16,
color: '#22203A',
textAlign: 'center',
}}>
Sell
</Text>
</Pressable>
<Pressable
accessibilityRole="button"
style={{
height: 64,
borderWidth: 0,
borderRadius: 32,
backgroundColor: '#22203A',
flex: 1,
alignItems: 'center',
justifyContent: 'center',
}}>
<Text
style={{
fontFamily: 'IBMPlexSans_500Medium',
fontSize: 16,
color: '#FFFFFF',
textAlign: 'center',
}}>
Buy
</Text>
</Pressable>
</View>
</View>
</View>
</Screen>
);
}src/app/index.tsx
import { Pressable, Text, View } from 'react-native';
import Svg, { Circle, G, Text as SvgText } from 'react-native-svg';
import { Screen } from '@/components/screen';
const accent = '#6E5ED0';
export default function MainScreen() {
return (
<Screen background={accent} statusBar="light">
<View style={{ flex: 1 }}>
<Svg
width="390"
height="520"
viewBox="0 0 390 520"
style={{ position: 'absolute', top: 0, left: 0 }}>
<G fill="#22203A">
<Circle cx="150" cy="210" r="74" />
<Circle cx="70" cy="300" r="78" />
<Circle cx="190" cy="330" r="96" />
<Circle cx="300" cy="300" r="70" />
<Circle cx="250" cy="200" r="48" />
<Circle cx="350" cy="230" r="38" />
<Circle cx="40" cy="380" r="56" />
<Circle cx="330" cy="370" r="58" />
<Circle cx="120" cy="410" r="60" />
<Circle cx="250" cy="420" r="56" />
</G>
<Circle cx="250" cy="215" r="58" fill="#3A3854" opacity="0.9" />
<Circle cx="238" cy="198" r="22" fill="#5A5878" opacity="0.6" />
<Circle cx="40" cy="320" r="70" fill="none" stroke="#F4F1A6" strokeWidth="2" />
<Circle
cx="280"
cy="370"
r="46"
fill="none"
stroke="#FFFFFF"
strokeWidth="1.5"
opacity="0.85"
/>
<Circle
cx="250"
cy="390"
r="28"
fill="none"
stroke="#FFFFFF"
strokeWidth="1.5"
opacity="0.85"
/>
<Circle cx="372" cy="255" r="14" fill="none" stroke="#F4F1A6" strokeWidth="2" />
<Circle
cx="440"
cy="40"
r="330"
fill="none"
stroke="#FFFFFF"
strokeWidth="1"
opacity="0.18"
/>
<Circle
cx="310"
cy="95"
r="40"
fill="#FFFFFF"
fillOpacity="0.12"
stroke="#FFFFFF"
strokeOpacity="0.45"
/>
<SvgText
x="310"
y="108"
transform="rotate(-15 310 95)"
textAnchor="middle"
fontFamily="IBMPlexSans_500Medium"
fontSize="36"
fill="#FFFFFF">
$
</SvgText>
<Circle
cx="130"
cy="150"
r="32"
fill="#FFFFFF"
fillOpacity="0.12"
stroke="#FFFFFF"
strokeOpacity="0.45"
/>
<SvgText
x="130"
y="160"
textAnchor="middle"
fontFamily="IBMPlexSans_600SemiBold"
fontSize="26"
fill="#FFFFFF">
₿
</SvgText>
</Svg>
<View style={{ position: 'absolute', left: 40, right: 40, bottom: 96, gap: 56 }}>
<Text
style={{
margin: 0,
fontFamily: 'Exo2_300Light',
fontSize: 42,
color: '#FFFFFF',
letterSpacing: 0.3,
lineHeight: 46.2,
}}>
{'Trusted & Secure Crypto Wallet'}
</Text>
<Pressable
accessibilityRole="button"
style={{
alignSelf: 'center',
width: 200,
height: 56,
borderWidth: 0,
borderRadius: 28,
backgroundColor: '#F4F1A6',
alignItems: 'center',
justifyContent: 'center',
}}>
<Text
style={{
fontFamily: 'IBMPlexSans_500Medium',
fontSize: 16,
color: '#22203A',
textAlign: 'center',
}}>
Next
</Text>
</Pressable>
</View>
<View
style={{
position: 'absolute',
left: '50%',
bottom: 72,
width: 24,
height: 3,
marginLeft: -12,
borderRadius: 2,
backgroundColor: '#22203A',
}}
/>
</View>
</Screen>
);
}src/app/wallet.tsx
import { Pressable, Text, View } from 'react-native';
import Svg, { Circle, G, Path, Polyline, Rect } from 'react-native-svg';
import { Screen } from '@/components/screen';
export default function WalletScreen() {
return (
<Screen background="#FFFFFF" statusBar="dark">
<View style={{ flex: 1 }}>
<View style={{ paddingTop: 56, paddingBottom: 0, paddingHorizontal: 24, gap: 0 }}>
<View
style={{ alignItems: 'center', justifyContent: 'space-between', flexDirection: 'row' }}>
<Svg
width="22"
height="22"
viewBox="0 0 22 22"
accessibilityRole="image"
accessibilityLabel="Wallet logo">
<Circle cx="6" cy="6" r="3.5" fill="none" stroke="#22203A" strokeWidth="1.6" />
<Circle cx="16" cy="6" r="3.5" fill="none" stroke="#22203A" strokeWidth="1.6" />
<Circle cx="6" cy="16" r="3.5" fill="none" stroke="#22203A" strokeWidth="1.6" />
</Svg>
<View style={{ alignItems: 'center', gap: 12, flexShrink: 1, flexDirection: 'row' }}>
<Pressable
accessibilityRole="button"
accessibilityLabel="Add card"
style={{
width: 44,
height: 44,
borderWidth: 0,
borderRadius: 22,
backgroundColor: '#F1F0F6',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg width="16" height="16" viewBox="0 0 16 16">
<Path
d="M8 2v12M2 8h12"
stroke="#22203A"
strokeWidth="1.8"
strokeLinecap="round"
/>
</Svg>
</Pressable>
<Pressable
accessibilityRole="button"
accessibilityLabel="Linked cards"
style={{
height: 44,
paddingVertical: 0,
paddingLeft: 14,
paddingRight: 6,
borderWidth: 0,
borderRadius: 22,
backgroundColor: '#22203A',
alignItems: 'center',
gap: 8,
flexShrink: 1,
flexDirection: 'row',
}}>
<Text
style={{
flexShrink: 1,
fontFamily: 'IBMPlexSans_600SemiBold',
fontSize: 11,
color: '#FFFFFF',
fontStyle: 'italic',
}}>
VISA
</Text>
<View
style={{
width: 32,
height: 32,
borderRadius: 16,
backgroundColor: '#FFFFFF',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg width="22" height="14" viewBox="0 0 22 14">
<Circle cx="7" cy="7" r="6" fill="#22203A" />
<Circle cx="15" cy="7" r="6" fill="none" stroke="#22203A" strokeWidth="1.6" />
</Svg>
</View>
</Pressable>
</View>
</View>
<Text
style={{
marginTop: 32,
marginBottom: 6,
marginHorizontal: 0,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 14,
color: '#6B6880',
}}>
Current value
</Text>
<Text
style={{
margin: 0,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 44,
color: '#22203A',
letterSpacing: -1,
}}>
$30,540<Text style={{ color: '#8E8BA0' }}>.00</Text>
</Text>
<View style={{ marginTop: 20, alignItems: 'center', gap: 10, flexDirection: 'row' }}>
<Pressable
accessibilityRole="button"
style={{
flex: 1,
height: 48,
borderWidth: 0,
borderRadius: 24,
backgroundColor: '#F1F0F6',
alignItems: 'center',
gap: 12,
paddingVertical: 0,
paddingHorizontal: 6,
flexDirection: 'row',
}}>
<View
style={{
width: 36,
height: 36,
borderRadius: 18,
backgroundColor: '#D9D4F7',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg width="14" height="14" viewBox="0 0 14 14">
<Path
d="M7 11V3M3.5 6.5 7 3l3.5 3.5M2 13h10"
fill="none"
stroke="#22203A"
strokeWidth="1.6"
strokeLinecap="round"
strokeLinejoin="round"
/>
</Svg>
</View>
<Text
style={{
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 13,
color: '#22203A',
flexShrink: 1,
}}>
Transfer
</Text>
</Pressable>
<Pressable
accessibilityRole="button"
accessibilityLabel="Swap"
style={{
width: 44,
height: 44,
flexGrow: 0,
flexShrink: 0,
borderWidth: 0,
borderRadius: 22,
backgroundColor: '#D9D4F7',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg width="16" height="16" viewBox="0 0 16 16">
<Path
d="M2 4h3l6 8h3M2 12h3l2-2.7M9 6.7 11 4h3M12 2l2 2-2 2M12 10l2 2-2 2"
fill="none"
stroke="#22203A"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</Svg>
</Pressable>
<Pressable
accessibilityRole="button"
style={{
flex: 1,
height: 48,
borderWidth: 0,
borderRadius: 24,
backgroundColor: '#F1F0F6',
alignItems: 'center',
justifyContent: 'space-between',
paddingVertical: 0,
paddingLeft: 20,
paddingRight: 6,
flexDirection: 'row',
}}>
<Text
style={{
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 13,
color: '#22203A',
flexShrink: 1,
}}>
Receive
</Text>
<View
style={{
width: 36,
height: 36,
borderRadius: 18,
backgroundColor: '#D9D4F7',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg width="14" height="14" viewBox="0 0 14 14">
<Path
d="M7 1v8M3.5 5.5 7 9l3.5-3.5M2 13h10"
fill="none"
stroke="#22203A"
strokeWidth="1.6"
strokeLinecap="round"
strokeLinejoin="round"
/>
</Svg>
</View>
</Pressable>
</View>
<Text
style={{
marginTop: 28,
marginBottom: 12,
marginHorizontal: 0,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 14,
color: '#6B6880',
}}>
Favourites
</Text>
<View style={{ flexDirection: 'row', gap: 14 }}>
<View
style={{
backgroundColor: '#F4F1A6',
borderRadius: 28,
paddingTop: 20,
paddingBottom: 16,
paddingHorizontal: 16,
gap: 6,
flex: 1,
}}>
<Text
style={{
margin: 0,
fontFamily: 'IBMPlexSans_500Medium',
fontSize: 20,
color: '#22203A',
textAlign: 'center',
}}>
$1467.64
</Text>
<Text
style={{
margin: 0,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 11,
color: '#3B3852',
textAlign: 'center',
}}>
↗ +9.0%
</Text>
<Svg width="100%" height="56" viewBox="0 0 140 56" preserveAspectRatio="none">
<Polyline
points="0,44 14,40 26,46 40,36 52,40 66,30 78,34 92,22 104,26 118,12 130,16 140,6"
fill="none"
stroke="#22203A"
strokeWidth="1.6"
strokeLinejoin="round"
/>
</Svg>
<View style={{ alignItems: 'center', gap: 10, flexDirection: 'row' }}>
<View
style={{
width: 40,
height: 40,
borderRadius: 20,
backgroundColor: '#FFFFFF',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg width="18" height="18" viewBox="0 0 18 18">
<Path
d="M3 4c2 2 3.5 3 6 3s4-1 6-3M3 14c2-2 3.5-3 6-3s4 1 6 3"
fill="none"
stroke="#22203A"
strokeWidth="1.6"
strokeLinecap="round"
/>
</Svg>
</View>
<View style={{ flexShrink: 1 }}>
<Text
style={{
margin: 0,
fontFamily: 'IBMPlexSans_500Medium',
fontSize: 14,
color: '#22203A',
}}>
Ripple
</Text>
<Text
style={{
margin: 0,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 11,
color: '#4D4A63',
}}>
XRP
</Text>
</View>
</View>
</View>
<View
style={{
backgroundColor: '#DCC9F6',
borderRadius: 28,
paddingTop: 20,
paddingBottom: 16,
paddingHorizontal: 16,
gap: 6,
flex: 1,
}}>
<Text
style={{
margin: 0,
fontFamily: 'IBMPlexSans_500Medium',
fontSize: 20,
color: '#22203A',
textAlign: 'center',
}}>
$195.00
</Text>
<Text
style={{
margin: 0,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 11,
color: '#3B3852',
textAlign: 'center',
}}>
↗ +1.4%
</Text>
<Svg width="100%" height="56" viewBox="0 0 140 56" preserveAspectRatio="none">
<Polyline
points="0,40 12,30 22,36 34,26 46,34 58,24 68,30 80,20 92,32 104,22 116,28 128,14 140,20"
fill="none"
stroke="#22203A"
strokeWidth="1.6"
strokeLinejoin="round"
/>
</Svg>
<View style={{ alignItems: 'center', gap: 10, flexDirection: 'row' }}>
<View
style={{
width: 40,
height: 40,
borderRadius: 20,
backgroundColor: '#FFFFFF',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg width="14" height="20" viewBox="0 0 14 20">
<Path
d="M7 1 1 10l6 3.5 6-3.5L7 1ZM1 11.5 7 19l6-7.5-6 3.5-6-3.5Z"
fill="#22203A"
/>
</Svg>
</View>
<View style={{ flexShrink: 1 }}>
<Text
style={{
margin: 0,
fontFamily: 'IBMPlexSans_500Medium',
fontSize: 14,
color: '#22203A',
}}>
Ethereum
</Text>
<Text
style={{
margin: 0,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 11,
color: '#4D4A63',
}}>
ETH
</Text>
</View>
</View>
</View>
</View>
<Text
style={{
marginTop: 26,
marginBottom: 12,
marginHorizontal: 0,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 14,
color: '#6B6880',
}}>
Assets
</Text>
<View
style={{
backgroundColor: '#F1F0F6',
borderRadius: 22,
paddingVertical: 14,
paddingLeft: 14,
paddingRight: 18,
alignItems: 'center',
gap: 14,
flexDirection: 'row',
}}>
<View
style={{
width: 40,
height: 40,
borderRadius: 20,
backgroundColor: '#FFFFFF',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Text
style={{
fontFamily: 'IBMPlexSans_600SemiBold',
fontSize: 18,
color: '#22203A',
flexShrink: 1,
}}>
₿
</Text>
</View>
<View style={{ flex: 1 }}>
<Text
style={{
margin: 0,
fontFamily: 'IBMPlexSans_500Medium',
fontSize: 14,
color: '#22203A',
}}>
Bitcoin
</Text>
<Text
style={{
margin: 0,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 11,
color: '#6B6880',
}}>
BTC
</Text>
</View>
<View style={{ flexShrink: 1 }}>
<Text
style={{
margin: 0,
fontFamily: 'IBMPlexSans_500Medium',
fontSize: 14,
color: '#22203A',
textAlign: 'right',
}}>
$10,265.016
</Text>
<Text
style={{
margin: 0,
fontFamily: 'IBMPlexSans_400Regular',
fontSize: 11,
color: '#4D4A63',
textAlign: 'right',
}}>
+12.32%
</Text>
</View>
</View>
</View>
<View style={{ position: 'absolute', left: 0, right: 0, bottom: 0, height: 100 }}>
<Svg
width="390"
height="100"
viewBox="0 0 390 100"
style={{ position: 'absolute', left: 0, bottom: 0 }}>
<Path
d="M0 18 C30 10 60 5 95 4 C118 3 130 5 138 9 C144 12 148 16 148 21 A47 47 0 0 0 242 21 C242 16 246 12 252 9 C260 5 272 3 290 3 C325 4 360 12 390 21 L390 100 L0 100 Z"
fill="#22203A"
/>
</Svg>
<Pressable
accessibilityRole="button"
accessibilityLabel="New transaction"
style={{
position: 'absolute',
left: 160,
top: -14,
width: 70,
height: 70,
borderRadius: 35,
borderWidth: 0,
backgroundColor: '#D2D6FA',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg width="22" height="22" viewBox="0 0 22 22">
<Path d="M11 2v18M2 11h18" stroke="#22203A" strokeWidth="1.6" strokeLinecap="round" />
</Svg>
</Pressable>
<Pressable
accessibilityRole="button"
accessibilityLabel="Home"
style={{
position: 'absolute',
left: 24,
top: 26,
width: 48,
height: 48,
borderWidth: 0,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg width="24" height="24" viewBox="0 0 24 24">
<Path
d="M4 10.2c0-.6.3-1.2.8-1.6l6-4.6c.7-.5 1.7-.5 2.4 0l6 4.6c.5.4.8 1 .8 1.6V19c0 1.1-.9 2-2 2H6c-1.1 0-2-.9-2-2Z"
fill="#FFFFFF"
/>
</Svg>
</Pressable>
<Pressable
accessibilityRole="button"
accessibilityLabel="Markets"
style={{
position: 'absolute',
left: 84,
top: 26,
width: 48,
height: 48,
borderWidth: 0,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg width="24" height="24" viewBox="0 0 24 24">
<G fill="none" stroke="#FFFFFF" strokeWidth="1.6">
<Rect x="2.5" y="15" width="5" height="6" rx="2.5" />
<Rect x="9.5" y="10" width="5" height="11" rx="2.5" />
<Rect x="16.5" y="5" width="5" height="16" rx="2.5" />
</G>
</Svg>
</Pressable>
<Pressable
accessibilityRole="button"
accessibilityLabel="Wallets"
style={{
position: 'absolute',
left: 260,
top: 26,
width: 48,
height: 48,
borderWidth: 0,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg width="24" height="24" viewBox="0 0 24 24">
<G fill="none" stroke="#FFFFFF" strokeWidth="1.6">
<Circle cx="12" cy="12" r="9" />
<Path d="M21 9.5h-4.5a2.5 2.5 0 0 0 0 5H21" />
</G>
</Svg>
</Pressable>
<Pressable
accessibilityRole="button"
accessibilityLabel="Profile"
style={{
position: 'absolute',
left: 316,
top: 26,
width: 48,
height: 48,
borderWidth: 0,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg width="24" height="24" viewBox="0 0 24 24">
<G fill="none" stroke="#FFFFFF" strokeWidth="1.6">
<Circle cx="12" cy="7.5" r="4" />
<Rect x="4.5" y="14" width="15" height="7" rx="3.5" />
</G>
</Svg>
</Pressable>
</View>
</View>
</Screen>
);
}src/components/screen.tsx
import { StatusBar } from 'expo-status-bar';
import type { ReactNode } from 'react';
import { ScrollView, useWindowDimensions, View } from 'react-native';
// Every screen is drawn on a 390 x 844 artboard, then scaled to the device width.
const ARTBOARD_WIDTH = 390;
const ARTBOARD_HEIGHT = 844;
type Props = {
background: string;
statusBar: 'light' | 'dark';
children: ReactNode;
};
export function Screen({ background, statusBar, children }: Props) {
const { width, height } = useWindowDimensions();
const scale = width / ARTBOARD_WIDTH;
return (
<ScrollView
bounces={false}
showsVerticalScrollIndicator={false}
style={{ flex: 1, backgroundColor: background }}
contentContainerStyle={{ height: Math.max(ARTBOARD_HEIGHT * scale, height) }}>
<StatusBar style={statusBar} />
<View
style={{
width: ARTBOARD_WIDTH,
height: ARTBOARD_HEIGHT,
overflow: 'hidden',
transformOrigin: 'left top',
transform: [{ scale }],
}}>
{children}
</View>
</ScrollView>
);
}About this design
Every chart is drawn in SVG, so it stays crisp on any screen and you can drive it from live market data without adding a chart library.
Deep violet and pale lemon with light Exo 2 headlines, soft pastel cards and a curved tab bar around a raised action.
- Candlestick chart drawn in plain SVG
- Sparkline favourites cards
- Curved tab bar with a raised action button
- Time range tabs and buy and sell actions
Colour palette
Deep violet
#22203A
Iris
#6E5ED0
Lemon
#F4F1A6
Periwinkle
#CBCDF8
Lavender
#DCC9F6
Mist
#F1F0F6
How to use this design
- 01
Pick what to copy
Copy the Crypto Wallet artifact, skill or code from this page.
- 02
Run it or generate it
Paste the code into a new Expo app and start it, or give the skill to your AI coding agent.
- 03
Make it yours
Replace the demo images and sample content, then connect your own data.
Frequently asked questions
Do I need a chart library for the candlesticks?
No. The chart is react-native-svg lines and rectangles, so you can map your own price data to the same elements.
Is the Crypto Wallet design free to use?
Yes. The design, skill and Expo code are free and MIT licensed, including for commercial apps. Replace the demo images and sample content with your own before you ship.
What is the difference between the artifact, skill and code?
The artifact is the full design: tokens, screens and source. The skill is a SKILL.md that teaches an AI coding agent to build the UI. The code is the finished Expo app you can paste in and run.
Which Expo version does the code use?
It targets Expo SDK 58 with Expo Router and TypeScript. It uses packages installed through npx expo install, with no custom native code.



