// Sports app UI
Basketball Stats and Streams App UI Design in Expo
This basketball app UI is built around game day energy. A season countdown opens the app, an event screen collects player stats and live matches, and a streams screen compares two teams in real time.
- Screens
- 3
- Built with
- Expo SDK 58
- Fonts
- Exo 2, Poppins
- License
- Free (MIT)

Courtside Basketball app screens

Season opener
A full-bleed player on a crimson court with a season countdown, feature labels and a Let's Play button.

Event hub
A headline beside a player cut-out, stat cards with a progress ring, a sport picker and live match cards.

Live streams
A live score card, team comparison rows with stat bars and a stream preview above the tab bar.
Copy the Courtside Basketball 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
# Courtside Basketball: design artifact
This basketball app UI is built around game day energy. A season countdown opens the app, an event screen collects player stats and live matches, and a streams screen compares two teams in real time.
- Type: Sports mobile app UI
- Screens: 3
- Artboard: 390 × 844
- Target: Expo SDK 58, Expo Router, TypeScript, expo-image, expo-linear-gradient, react-native-svg
- Live page: https://developermill.com/app-designs/basketball-tickets-app-ui-design
## Design direction
Coral to crimson gradients with sporty italic numbers, dark rounded stat panels and a cut-out player leading each screen.
- Season countdown hero with a player cut-out
- Sport picker and live match cards
- Team comparison rows for field goals and assists
- Coral gradient backgrounds with dark stat panels
## Foundations
### Colour
| Token | Hex |
| --- | --- |
| Crimson | `#C21F3A` |
| Rose | `#E2475A` |
| Coral | `#F07A5E` |
| Blush | `#FFE3E6` |
| Oxblood | `#2A0D10` |
| Night | `#1E0B0E` |
### Typography
- Typefaces: Exo 2, Poppins
- Common sizes (px): 10, 11, 12, 13, 14, 15, 16, 24
### Shape and depth
- Common corner radii (px): 3, 14, 16, 17, 22, 23
- Shadows: `inset 0 0 0 2px rgba(255,255,255,0.85)`, `0 12px 30px rgba(60,5,15,0.4)`, `0 10px 30px rgba(90,6,20,0.45)`
## Screens
### 1. Season opener
A full-bleed player on a crimson court with a season countdown, feature labels and a Let's Play button.
Preview: https://developermill.com/app-designs/basketball-tickets-app-ui-design/welcome.webp
Copy on this screen:
- 18
- Season
- Starts
- in
- Challenge
- Your Skills
- Play &
- Learn
- Quiz &
- Play
- Let's Play
### 2. Event hub
A headline beside a player cut-out, stat cards with a progress ring, a sport picker and live match cards.
Preview: https://developermill.com/app-designs/basketball-tickets-app-ui-design/event.webp
Copy on this screen:
- Event
- Catch Every
- Game
- Complete Game Stats
- 1650
- Player Points
- Completed
- Matches
- 72
- 90%
- Sports
- Basketball
- Live Matches
- VS
### 3. Live streams
A live score card, team comparison rows with stat bars and a stream preview above the tab bar.
Preview: https://developermill.com/app-designs/basketball-tickets-app-ui-design/streams.webp
Copy on this screen:
- Streams
- Live
- 08:30:22 PM
- MV
- 142
- VS
- 128
- BT
- MTV
- BYT
## Full source
The original artboards as HTML. Image URLs point at the hosted demo assets.
### Season opener (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="preconnect" href="https://fonts.googleapis.com">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Exo+2:wght@500;600;700;800&family=Poppins:wght@400;500;600&display=swap">
<style>
body{margin:0}
a{color:#fff}a:hover{color:#FFE3E6}
</style>
</helmet>
<div style="width: 390px; height: 844px; position: relative; overflow: hidden; font-family: 'Poppins', system-ui, sans-serif; color: #FFFFFF; background: linear-gradient(180deg, #6E0C1B 0%, #9E1427 30%, #C12B3E 58%, #DE7C86 80%, #B8243A 100%)">
<img src="https://developermill.com/app-designs/basketball-tickets-app-ui-design/assets/29dd54fa16.jpg" alt="Basketball player in a red #7 jersey dribbling low" style="position: absolute; left: 0; top: 0; width: 390px; height: 844px; object-fit: cover; object-position: center 60%">
<div style="position: absolute; left: 0; right: 0; top: 0; height: 320px; background: linear-gradient(180deg, rgba(110,12,27,0.55) 0%, rgba(110,12,27,0) 100%)"></div>
<div style="position: absolute; left: 0; right: 0; bottom: 0; height: 300px; background: linear-gradient(180deg, rgba(158,20,39,0) 0%, rgba(150,18,36,0.75) 70%, #8E1426 100%)"></div>
<div style="position: absolute; left: 22px; top: 150px; display: flex; align-items: center; gap: 12px">
<div style="font-family: 'Exo 2', sans-serif; font-weight: 800; font-size: 112px; line-height: 0.9; letter-spacing: -4px; color: #FFFFFF">18</div>
<div style="font-family: 'Exo 2', sans-serif; font-weight: 600; font-size: 40px; line-height: 1.05; color: #FFFFFF">
<div>Season</div>
<div>Starts <span style="color: #FFB8C1">in</span></div>
</div>
</div>
<div style="position: absolute; right: 22px; top: 470px; text-align: right; font-size: 13px; line-height: 1.6">
<div style="color: rgba(255,255,255,0.85)">Challenge</div>
<div style="font-weight: 600">Your Skills</div>
</div>
<div style="position: absolute; left: 22px; top: 560px; font-size: 13px; line-height: 1.6">
<div style="color: rgba(255,255,255,0.85)">Play &</div>
<div style="font-weight: 600">Learn</div>
</div>
<div style="position: absolute; left: 22px; top: 640px; font-size: 13px; line-height: 1.6">
<div style="color: rgba(255,255,255,0.85)">Quiz &</div>
<div style="font-weight: 600">Play</div>
</div>
<div style="position: absolute; left: 22px; bottom: 74px; display: flex; gap: 6px; align-items: center" aria-hidden="true">
<span style="width: 6px; height: 6px; border-radius: 3px; background: rgba(255,255,255,0.45)"></span>
<span style="width: 6px; height: 6px; border-radius: 3px; background: rgba(255,255,255,0.45)"></span>
<span style="width: 18px; height: 6px; border-radius: 3px; background: #FFFFFF"></span>
<span style="width: 6px; height: 6px; border-radius: 3px; background: rgba(255,255,255,0.45)"></span>
</div>
<a href="Event.dc.html" style="position: absolute; right: 22px; bottom: 36px; width: 96px; height: 96px; border-radius: 48px; box-sizing: border-box; border: 3px solid rgba(255,255,255,0.9); background: {{accent}}; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 600; color: #FFFFFF; text-decoration: none; box-shadow: 0 10px 30px rgba(90,6,20,0.45)">Let's Play</a>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"accent":{"editor":"color","default":"#E2475A","options":["#E2475A","#F07A5E","#C21F3A"]},"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
return { accent: this.props.accent ?? '#E2475A' };
}
}
</script>
</body>
</html>
```
### Event hub (Event)
```html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Event</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Exo+2:wght@500;600;700;800&family=Poppins:wght@400;500;600&display=swap">
<style>
body{margin:0}
a{color:#fff}a:hover{color:#FFE3E6}
</style>
</helmet>
<div style="width: 390px; height: 844px; position: relative; overflow: hidden; font-family: 'Poppins', system-ui, sans-serif; color: #FFFFFF; background: linear-gradient(180deg, #F8B29A 0%, #F39A86 32%, #E26472 62%, #C2304A 85%, #A11F37 100%)">
<div style="position: absolute; left: 20px; right: 20px; top: 58px; display: flex; align-items: center; justify-content: space-between">
<img src="https://developermill.com/app-designs/basketball-tickets-app-ui-design/assets/749545fb3c.jpg" alt="Your profile" style="width: 46px; height: 46px; border-radius: 23px; box-sizing: border-box; border: 2px solid #FFFFFF; object-fit: cover">
<div style="font-size: 16px; font-weight: 600; color: #2A0D10">Event</div>
<button aria-label="Open menu" style="width: 46px; height: 46px; border-radius: 23px; border: 0; background: #1E0B0E; display: flex; align-items: center; justify-content: center; cursor: pointer">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="1.8" stroke-linecap="round" aria-hidden="true"><path d="M5 7h14"></path><path d="M8 12h11"></path><path d="M11 17h8"></path></svg>
</button>
</div>
<div style="position: absolute; left: 20px; top: 128px; font-family: 'Exo 2', sans-serif; font-weight: 500; font-size: 46px; line-height: 1.08; color: #2A0D10; letter-spacing: -0.5px">
<div>Catch Every</div>
<div>Game</div>
</div>
<img src="https://developermill.com/app-designs/basketball-tickets-app-ui-design/assets/62c94f616b.png" alt="Player in a red #7 jersey holding a basketball" style="position: absolute; right: 4px; top: 96px; width: 160px; height: 200px; object-fit: cover; object-position: center top">
<div style="position: absolute; left: 20px; right: 20px; top: 286px; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px">
<div style="height: 168px; border-radius: 22px; background: #1E0B0E; box-sizing: border-box; padding: 12px; display: flex; flex-direction: column; justify-content: space-between">
<div style="display: flex; align-items: center; gap: 10px">
<div style="width: 44px; height: 44px; border-radius: 22px; background: #2E1418; display: flex; align-items: center; justify-content: center; flex-shrink: 0">
<svg width="24" height="24" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="10" fill="#F07A2E"></circle><path d="M2 12h20M12 2v20M5 5c3 3 3 11 0 14M19 5c-3 3-3 11 0 14" fill="none" stroke="#3A1405" stroke-width="1.2"></path></svg>
</div>
<div style="font-size: 13px; line-height: 1.35">Complete Game Stats</div>
</div>
<div style="display: flex; gap: 8px">
<div style="flex: 1; border-radius: 14px; background: #2E1418; padding: 8px 10px">
<div style="display: flex; align-items: center; gap: 4px; font-size: 13px; font-weight: 600"><svg width="12" height="12" viewBox="0 0 24 24" fill="#FFC24A" aria-hidden="true"><path d="M12 2l3 6.6 7 .8-5.2 4.8 1.4 7L12 17.8 5.8 21.2l1.4-7L2 9.4l7-.8z"></path></svg>1650</div>
<div style="font-size: 10px; color: rgba(255,255,255,0.7)">Player Points</div>
</div>
<button aria-label="Open game stats" style="width: 44px; border-radius: 14px; border: 0; background: #2E1418; display: flex; align-items: center; justify-content: center; cursor: pointer">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="1.8" stroke-linecap="round" aria-hidden="true"><path d="M7 17L17 7M9 7h8v8"></path></svg>
</button>
</div>
</div>
<div style="height: 168px; border-radius: 22px; background: #1E0B0E; box-sizing: border-box; padding: 14px; display: flex; flex-direction: column; justify-content: space-between">
<div style="font-size: 13px; line-height: 1.35">Completed<br>Matches</div>
<div style="display: flex; align-items: flex-end; justify-content: space-between">
<div style="font-family: 'Exo 2', sans-serif; font-size: 44px; font-weight: 500; line-height: 1">72</div>
<div style="position: relative; width: 58px; height: 58px">
<svg width="58" height="58" viewBox="0 0 58 58" aria-hidden="true"><circle cx="29" cy="29" r="24" fill="none" stroke="#3A1A1E" stroke-width="5"></circle><circle cx="29" cy="29" r="24" fill="none" stroke="{{accent}}" stroke-width="5" stroke-linecap="round" stroke-dasharray="135.7 150.8" transform="rotate(-90 29 29)"></circle></svg>
<div style="position: absolute; left: 0; top: 0; width: 58px; height: 58px; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 600">90%</div>
</div>
</div>
</div>
</div>
<div style="position: absolute; left: 20px; top: 478px; font-size: 14px; font-weight: 500; color: #FFFFFF">Sports</div>
<div style="position: absolute; left: 20px; right: 0; top: 508px; display: flex; gap: 10px; align-items: center">
<button aria-label="Football" style="width: 46px; height: 46px; border-radius: 23px; border: 0; background: rgba(30,11,14,0.55); display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#F3C34A" stroke-width="1.6" aria-hidden="true"><ellipse cx="12" cy="12" rx="10" ry="6" transform="rotate(-40 12 12)"></ellipse><path d="M9 15l6-6M10 11l3 3M12 9l3 3"></path></svg></button>
<button style="height: 46px; border-radius: 23px; border: 0; background: #1E0B0E; display: flex; align-items: center; gap: 10px; padding: 0 18px 0 6px; color: #FFFFFF; font-family: inherit; font-size: 13px; font-weight: 600"><span style="width: 34px; height: 34px; border-radius: 17px; background: #2E1418; display: flex; align-items: center; justify-content: center"><svg width="20" height="20" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="10" fill="#F07A2E"></circle><path d="M2 12h20M12 2v20M5 5c3 3 3 11 0 14M19 5c-3 3-3 11 0 14" fill="none" stroke="#3A1405" stroke-width="1.2"></path></svg></span>Basketball</button>
<button aria-label="Volleyball" style="width: 46px; height: 46px; border-radius: 23px; border: 0; background: rgba(30,11,14,0.55); display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#B9A7FF" stroke-width="1.6" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><path d="M12 2c0 6 4 9 9 11M3 8c5 1 9 5 9 14M5 19c4-5 10-6 15-5"></path></svg></button>
<button aria-label="Tennis" style="width: 46px; height: 46px; border-radius: 23px; border: 0; background: rgba(30,11,14,0.55); display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#9BE37A" stroke-width="1.6" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><path d="M5 5c4 4 4 10 0 14M19 5c-4 4-4 10 0 14"></path></svg></button>
<button aria-label="Cricket" style="width: 46px; height: 46px; border-radius: 23px; border: 0; background: rgba(30,11,14,0.55); display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#FF9AA8" stroke-width="1.6" stroke-linecap="round" aria-hidden="true"><path d="M4 20l9-9 3 3-9 9z"></path><path d="M14 10l5-5"></path><circle cx="18" cy="17" r="2.5"></circle></svg></button>
</div>
<div style="position: absolute; left: 20px; right: 20px; top: 576px; display: flex; align-items: center; justify-content: space-between">
<div style="font-size: 14px; font-weight: 500">Live Matches</div>
<div style="display: flex; gap: 5px; align-items: center" aria-hidden="true"><span style="width: 5px; height: 5px; border-radius: 3px; background: rgba(255,255,255,0.5)"></span><span style="width: 14px; height: 5px; border-radius: 3px; background: #FFFFFF"></span><span style="width: 5px; height: 5px; border-radius: 3px; background: rgba(255,255,255,0.5)"></span></div>
</div>
<div style="position: absolute; left: 20px; right: 20px; top: 604px; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px">
<sc-for list="{{matches}}" as="m" hint-placeholder-count="2">
<div style="border-radius: 20px; background: #1E0B0E; padding: 12px 14px; box-sizing: border-box">
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px">
<div style="width: 34px; height: 34px; border-radius: 17px; background: {{m.c1}}; display: flex; align-items: center; justify-content: center; font-family: 'Exo 2', sans-serif; font-size: 11px; font-weight: 700; color: #FFFFFF; box-shadow: inset 0 0 0 2px rgba(255,255,255,0.85)">{{m.a1}}</div>
<div style="font-size: 13px; font-weight: 600">VS</div>
<div style="width: 34px; height: 34px; border-radius: 17px; background: {{m.c2}}; display: flex; align-items: center; justify-content: center; font-family: 'Exo 2', sans-serif; font-size: 11px; font-weight: 700; color: #FFFFFF; box-shadow: inset 0 0 0 2px rgba(255,255,255,0.85)">{{m.a2}}</div>
</div>
<div style="display: flex; justify-content: space-between; font-size: 12px; line-height: 1.7"><span style="color: rgba(255,255,255,0.75)">{{m.t1}}</span><span style="font-weight: 600">{{m.s1}}</span></div>
<div style="display: flex; justify-content: space-between; font-size: 12px; line-height: 1.7"><span style="color: rgba(255,255,255,0.75)">{{m.t2}}</span><span style="font-weight: 600">{{m.s2}}</span></div>
</div>
</sc-for>
</div>
<nav aria-label="Main" style="position: absolute; left: 32px; right: 32px; bottom: 30px; height: 64px; border-radius: 32px; background: #1E0B0E; display: flex; align-items: center; justify-content: space-around; padding: 0 6px; box-shadow: 0 12px 30px rgba(60,5,15,0.4)">
<a href="Event.dc.html" aria-label="Home" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="1.7" stroke-linejoin="round" aria-hidden="true"><path d="M4 10l8-6 8 6v9a1 1 0 0 1-1 1h-4v-6H9v6H5a1 1 0 0 1-1-1z"></path></svg></a>
<a href="Event.dc.html" aria-label="Search" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="1.7" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"></circle><path d="M20 20l-4-4"></path></svg></a>
<a href="Event.dc.html" aria-label="Favorites" style="width: 52px; height: 52px; border-radius: 26px; background: {{accent}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="1.7" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l2.7 5.8 6.3.7-4.7 4.3 1.3 6.2L12 17l-5.6 3 1.3-6.2L3 9.5l6.3-.7z"></path></svg></a>
<a href="Streams.dc.html" aria-label="Live streams" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="1.7" stroke-linecap="round" aria-hidden="true"><circle cx="12" cy="12" r="2"></circle><path d="M8.5 8.5a5 5 0 0 0 0 7M15.5 8.5a5 5 0 0 1 0 7M5.6 5.6a9 9 0 0 0 0 12.8M18.4 5.6a9 9 0 0 1 0 12.8"></path></svg></a>
<a href="Event.dc.html" aria-label="Profile" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="1.7" stroke-linecap="round" aria-hidden="true"><circle cx="12" cy="8" r="4"></circle><path d="M4 21c1.5-4 4.5-6 8-6s6.5 2 8 6"></path></svg></a>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"accent":{"editor":"color","default":"#E2475A","options":["#E2475A","#F07A5E","#C21F3A"]},"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
return {
accent: this.props.accent ?? '#E2475A',
matches: [
{ a1: 'HB', c1: '#1F5FBF', t1: 'HBH', s1: '135', a2: 'RC', c2: '#D2362F', t2: 'RDC', s2: '129' },
{ a1: 'MV', c1: '#5B3FC4', t1: 'MTV', s1: '142', a2: 'BT', c2: '#0F7A6B', t2: 'BYT', s2: '128' }
]
};
}
}
</script>
</body>
</html>
```
### Live streams (Streams)
```html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Streams</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Exo+2:wght@500;600;700;800&family=Poppins:wght@400;500;600&display=swap">
<style>
body{margin:0}
a{color:#fff}a:hover{color:#FFE3E6}
</style>
</helmet>
<div style="width: 390px; height: 844px; position: relative; overflow: hidden; font-family: 'Poppins', system-ui, sans-serif; color: #FFFFFF; background: linear-gradient(180deg, #F8B29A 0%, #F39A86 30%, #E26472 58%, #C2304A 82%, #A11F37 100%)">
<div style="position: absolute; left: 20px; right: 20px; top: 58px; display: flex; align-items: center; justify-content: space-between">
<img src="https://developermill.com/app-designs/basketball-tickets-app-ui-design/assets/749545fb3c.jpg" alt="Your profile" style="width: 46px; height: 46px; border-radius: 23px; box-sizing: border-box; border: 2px solid #FFFFFF; object-fit: cover">
<div style="font-size: 16px; font-weight: 600; color: #2A0D10">Streams</div>
<button aria-label="Notifications" style="width: 46px; height: 46px; border-radius: 23px; border: 0; background: #1E0B0E; display: flex; align-items: center; justify-content: center; cursor: pointer">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 16V11a6 6 0 0 1 12 0v5l2 2H4z"></path><path d="M10 21h4"></path></svg>
</button>
</div>
<div style="position: absolute; left: 20px; right: 20px; top: 126px; border-radius: 24px; background: #1E0B0E; padding: 14px; box-sizing: border-box">
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px">
<div style="display: flex; align-items: center; gap: 6px; font-size: 15px; font-weight: 600; color: #FF5A6E"><span style="width: 7px; height: 7px; border-radius: 4px; background: #FF5A6E"></span>Live</div>
<div style="display: flex; align-items: center; gap: 8px; background: #2E1418; border-radius: 14px; padding: 6px 12px 6px 8px; font-size: 11px">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="1.7" stroke-linecap="round" aria-hidden="true"><circle cx="12" cy="12" r="9"></circle><path d="M12 7v5l3 2"></path></svg>08:30:22 PM
</div>
</div>
<div style="display: flex; align-items: center; gap: 10px">
<div style="flex: 1; display: flex; align-items: center; justify-content: space-between; background: #2E1418; border-radius: 16px; padding: 10px 14px">
<div style="width: 38px; height: 38px; border-radius: 19px; background: #5B3FC4; display: flex; align-items: center; justify-content: center; font-family: 'Exo 2', sans-serif; font-size: 12px; font-weight: 700; box-shadow: inset 0 0 0 2px rgba(255,255,255,0.85)">MV</div>
<div style="font-family: 'Exo 2', sans-serif; font-size: 24px; font-weight: 600">142</div>
</div>
<div style="font-size: 14px; font-weight: 600">VS</div>
<div style="flex: 1; display: flex; align-items: center; justify-content: space-between; background: #2E1418; border-radius: 16px; padding: 10px 14px">
<div style="font-family: 'Exo 2', sans-serif; font-size: 24px; font-weight: 600">128</div>
<div style="width: 38px; height: 38px; border-radius: 19px; background: #0F7A6B; display: flex; align-items: center; justify-content: center; font-family: 'Exo 2', sans-serif; font-size: 12px; font-weight: 700; box-shadow: inset 0 0 0 2px rgba(255,255,255,0.85)">BT</div>
</div>
</div>
<div style="display: flex; justify-content: space-between; margin-top: 10px; font-size: 13px; font-weight: 600"><span>MTV</span><span>BYT</span></div>
</div>
<div style="position: absolute; left: 20px; right: 20px; top: 330px; display: flex; flex-direction: column; gap: 10px">
<sc-for list="{{stats}}" as="s" hint-placeholder-count="4">
<div style="display: flex; align-items: center; justify-content: space-between">
<div style="margin-left: {{s.indent}}; width: 152px; height: 58px; box-sizing: border-box; border-radius: 16px; background: {{s.bg}}; padding: 0 10px 0 14px; display: flex; align-items: center; justify-content: space-between; gap: 8px">
<div style="font-size: 12px; line-height: 1.35">{{s.label}}</div>
<div style="display: flex; flex-direction: column; gap: 3px" aria-hidden="true"><span style="width: 5px; height: {{s.red}}; border-radius: 3px; background: #FF5A6E"></span><span style="width: 5px; height: {{s.green}}; border-radius: 3px; background: #4ADE80"></span></div>
</div>
<div style="width: 92px; height: 58px; border-radius: 16px; background: rgba(110,15,30,0.45); display: flex; align-items: center; justify-content: center; font-size: 13px; font-weight: 600">{{s.value}}</div>
</div>
</sc-for>
</div>
<div style="position: absolute; left: 20px; right: 20px; top: 604px; height: 240px; border-radius: 26px; overflow: hidden; background: linear-gradient(160deg, #3A1218 0%, #1E0B0E 100%)">
<img src="https://developermill.com/app-designs/basketball-tickets-app-ui-design/assets/d3d8973874.jpg" alt="Live stream: player dunking at the hoop" style="position: absolute; left: 0; top: 0; width: 100%; height: 100%; object-fit: cover; object-position: 60% 20%">
<div style="position: absolute; right: 16px; top: 18px; background: rgba(30,11,14,0.7); border-radius: 12px; padding: 4px 12px; font-size: 11px; font-weight: 600">Live</div>
</div>
<nav aria-label="Main" style="position: absolute; left: 32px; right: 32px; bottom: 30px; height: 64px; border-radius: 32px; background: rgba(30,11,14,0.92); display: flex; align-items: center; justify-content: space-around; padding: 0 6px; box-shadow: 0 12px 30px rgba(60,5,15,0.4)">
<a href="Event.dc.html" aria-label="Home" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="1.7" stroke-linejoin="round" aria-hidden="true"><path d="M4 10l8-6 8 6v9a1 1 0 0 1-1 1h-4v-6H9v6H5a1 1 0 0 1-1-1z"></path></svg></a>
<a href="Event.dc.html" aria-label="Search" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="1.7" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"></circle><path d="M20 20l-4-4"></path></svg></a>
<a href="Event.dc.html" aria-label="Favorites" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="1.7" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l2.7 5.8 6.3.7-4.7 4.3 1.3 6.2L12 17l-5.6 3 1.3-6.2L3 9.5l6.3-.7z"></path></svg></a>
<a href="Streams.dc.html" aria-label="Live streams" style="width: 52px; height: 52px; border-radius: 26px; background: {{accent}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="1.7" stroke-linecap="round" aria-hidden="true"><circle cx="12" cy="12" r="2"></circle><path d="M8.5 8.5a5 5 0 0 0 0 7M15.5 8.5a5 5 0 0 1 0 7M5.6 5.6a9 9 0 0 0 0 12.8M18.4 5.6a9 9 0 0 1 0 12.8"></path></svg></a>
<a href="Event.dc.html" aria-label="Profile" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="1.7" stroke-linecap="round" aria-hidden="true"><circle cx="12" cy="8" r="4"></circle><path d="M4 21c1.5-4 4.5-6 8-6s6.5 2 8 6"></path></svg></a>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"accent":{"editor":"color","default":"#E2475A","options":["#E2475A","#F07A5E","#C21F3A"]},"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
return {
accent: this.props.accent ?? '#E2475A',
stats: [
{ label: 'Field Goals Attempt', value: '96 / 101', indent: '0px', bg: '#1E0B0E', red: '10px', green: '14px' },
{ label: 'Field Goals Made', value: '42 / 43', indent: '14px', bg: 'rgba(110,15,30,0.55)', red: '8px', green: '16px' },
{ label: 'Total Field Goals %', value: '45 / 41', indent: '0px', bg: '#1E0B0E', red: '14px', green: '10px' },
{ label: 'Total Team Assists', value: '36 / 32', indent: '14px', bg: 'rgba(110,15,30,0.55)', red: '12px', green: '12px' }
]
};
}
}
</script>
</body>
</html>
```SKILL.md
Save as .claude/skills/basketball-tickets-app-ui/SKILL.md
--- name: basketball-tickets-app-ui description: Build the Courtside Basketball mobile app UI in Expo React Native. Use when asked to create a basketball app UI or a new screen in this visual style. --- # Courtside Basketball app UI Build this sports app UI in an Expo Router project with TypeScript. Reference: https://developermill.com/app-designs/basketball-tickets-app-ui-design ## Visual direction Coral to crimson gradients with sporty italic numbers, dark rounded stat panels and a cut-out player leading each screen. Keep these signature details: - Season countdown hero with a player cut-out - Sport picker and live match cards - Team comparison rows for field goals and assists - Coral gradient backgrounds with dark stat panels ## Set up ```bash npx expo install expo-image expo-linear-gradient react-native-svg @expo-google-fonts/exo-2 @expo-google-fonts/poppins expo-font ``` ## Tokens | Name | Hex | | --- | --- | | Crimson | `#C21F3A` | | Rose | `#E2475A` | | Coral | `#F07A5E` | | Blush | `#FFE3E6` | | Oxblood | `#2A0D10` | | Night | `#1E0B0E` | - Typefaces: Exo 2, Poppins - Text sizes (px): 10, 11, 12, 13, 14, 15, 16, 24 - Corner radii (px): 3, 14, 16, 17, 22, 23 Define these once and reuse them. Do not add new colours. ## Screens 1. **Season opener.** A full-bleed player on a crimson court with a season countdown, feature labels and a Let's Play button. 2. **Event hub.** A headline beside a player cut-out, stat cards with a progress ring, a sport picker and live match cards. 3. **Live streams.** A live score card, team comparison rows with stat bars and a stream preview above the tab bar. ## Build rules - Draw each screen on a 390 × 844 artboard and scale it to the device width. - Load each custom font weight by family name with expo-font. Do not set fontWeight with custom fonts. - Draw icons, charts and illustrations with react-native-svg. - Use Pressable with an accessibilityLabel for controls, with at least a 44px target. - Navigate with router.navigate and keep sample data as constants at the top of the file. - Use expo-image with contentFit for photos. ## Done when - All routes are linked and reachable. - Colours, type and radii match the tokens above. - `npx tsc --noEmit` and `npx expo lint` pass. - The layout holds up on small and large phones.
Set up the project
npx create-expo-app@latest basketball-tickets-app --template default cd basketball-tickets-app rm -rf src npx expo install expo-image expo-linear-gradient react-native-svg @expo-google-fonts/exo-2 @expo-google-fonts/poppins expo-font
src/app/_layout.tsx
import {
Exo2_500Medium,
Exo2_600SemiBold,
Exo2_700Bold,
Exo2_800ExtraBold,
} from '@expo-google-fonts/exo-2';
import {
Poppins_400Regular,
Poppins_500Medium,
Poppins_600SemiBold,
} from '@expo-google-fonts/poppins';
import { useFonts } from 'expo-font';
import { Stack } from 'expo-router';
export default function RootLayout() {
const [fontsLoaded] = useFonts({
Exo2_500Medium,
Exo2_600SemiBold,
Exo2_700Bold,
Exo2_800ExtraBold,
Poppins_400Regular,
Poppins_500Medium,
Poppins_600SemiBold,
});
if (!fontsLoaded) return null;
return <Stack screenOptions={{ headerShown: false }} />;
}src/app/index.tsx
import { Image } from 'expo-image';
import { LinearGradient } from 'expo-linear-gradient';
import { router } from 'expo-router';
import { Pressable, StyleSheet, Text, View } from 'react-native';
import { Screen } from '@/components/screen';
import { asset } from '@/lib/assets';
const accent = '#E2475A';
export default function MainScreen() {
return (
<Screen background="#FFFFFF" statusBar="dark">
<View style={{ flex: 1 }}>
<LinearGradient
colors={['#6E0C1B', '#9E1427', '#C12B3E', '#DE7C86', '#B8243A']}
locations={[0, 0.3, 0.58, 0.8, 1]}
start={{ x: 0.5, y: 0 }}
end={{ x: 0.5, y: 1 }}
style={StyleSheet.absoluteFill}
/>
<Image
source={{ uri: asset('29dd54fa16.jpg') }}
contentFit="cover"
contentPosition={{ left: 'center', top: '60%' }}
accessibilityLabel="Basketball player in a red #7 jersey dribbling low"
style={{ position: 'absolute', left: 0, top: 0, width: 390, height: 844 }}
/>
<View style={{ position: 'absolute', left: 0, right: 0, top: 0, height: 320 }}>
<LinearGradient
colors={['rgba(110,12,27,0.55)', 'rgba(110,12,27,0)']}
locations={[0, 1]}
start={{ x: 0.5, y: 0 }}
end={{ x: 0.5, y: 1 }}
style={StyleSheet.absoluteFill}
/>
</View>
<View style={{ position: 'absolute', left: 0, right: 0, bottom: 0, height: 300 }}>
<LinearGradient
colors={['rgba(158,20,39,0)', 'rgba(150,18,36,0.75)', '#8E1426']}
locations={[0, 0.7, 1]}
start={{ x: 0.5, y: 0 }}
end={{ x: 0.5, y: 1 }}
style={StyleSheet.absoluteFill}
/>
</View>
<View
style={{
position: 'absolute',
left: 22,
top: 150,
alignItems: 'center',
gap: 12,
flexDirection: 'row',
}}>
<Text
style={{
flexShrink: 1,
fontFamily: 'Exo2_800ExtraBold',
fontSize: 112,
color: '#FFFFFF',
letterSpacing: -4,
lineHeight: 100.8,
}}>
18
</Text>
<View style={{ flexShrink: 1 }}>
<Text
style={{
fontFamily: 'Exo2_600SemiBold',
fontSize: 40,
color: '#FFFFFF',
lineHeight: 42,
}}>
Season
</Text>
<Text
style={{
fontFamily: 'Exo2_600SemiBold',
fontSize: 40,
color: '#FFFFFF',
lineHeight: 42,
}}>
{'Starts '}
<Text style={{ color: '#FFB8C1' }}>in</Text>
</Text>
</View>
</View>
<View style={{ position: 'absolute', right: 22, top: 470 }}>
<Text
style={{
fontFamily: 'Poppins_400Regular',
fontSize: 13,
color: 'rgba(255,255,255,0.85)',
lineHeight: 20.8,
textAlign: 'right',
}}>
Challenge
</Text>
<Text
style={{
fontFamily: 'Poppins_600SemiBold',
fontSize: 13,
color: '#FFFFFF',
lineHeight: 20.8,
textAlign: 'right',
}}>
Your Skills
</Text>
</View>
<View style={{ position: 'absolute', left: 22, top: 560 }}>
<Text
style={{
fontFamily: 'Poppins_400Regular',
fontSize: 13,
color: 'rgba(255,255,255,0.85)',
lineHeight: 20.8,
}}>
{'Play &'}
</Text>
<Text
style={{
fontFamily: 'Poppins_600SemiBold',
fontSize: 13,
color: '#FFFFFF',
lineHeight: 20.8,
}}>
Learn
</Text>
</View>
<View style={{ position: 'absolute', left: 22, top: 640 }}>
<Text
style={{
fontFamily: 'Poppins_400Regular',
fontSize: 13,
color: 'rgba(255,255,255,0.85)',
lineHeight: 20.8,
}}>
{'Quiz &'}
</Text>
<Text
style={{
fontFamily: 'Poppins_600SemiBold',
fontSize: 13,
color: '#FFFFFF',
lineHeight: 20.8,
}}>
Play
</Text>
</View>
<View
style={{
position: 'absolute',
left: 22,
bottom: 74,
gap: 6,
alignItems: 'center',
flexDirection: 'row',
}}>
<View
style={{
width: 6,
height: 6,
borderRadius: 3,
backgroundColor: 'rgba(255,255,255,0.45)',
}}
/>
<View
style={{
width: 6,
height: 6,
borderRadius: 3,
backgroundColor: 'rgba(255,255,255,0.45)',
}}
/>
<View style={{ width: 18, height: 6, borderRadius: 3, backgroundColor: '#FFFFFF' }} />
<View
style={{
width: 6,
height: 6,
borderRadius: 3,
backgroundColor: 'rgba(255,255,255,0.45)',
}}
/>
</View>
<Pressable
accessibilityRole="link"
onPress={() => router.navigate('/event')}
style={{
position: 'absolute',
right: 22,
bottom: 36,
width: 96,
height: 96,
borderRadius: 48,
borderWidth: 3,
borderColor: 'rgba(255,255,255,0.9)',
backgroundColor: accent,
alignItems: 'center',
justifyContent: 'center',
boxShadow: '0 10px 30px rgba(90,6,20,0.45)',
flexDirection: 'row',
}}>
<Text
style={{
fontFamily: 'Poppins_600SemiBold',
fontSize: 14,
color: '#FFFFFF',
flexShrink: 1,
}}>
{"Let's Play"}
</Text>
</Pressable>
</View>
</Screen>
);
}src/app/event.tsx
import { Image } from 'expo-image';
import { LinearGradient } from 'expo-linear-gradient';
import { router } from 'expo-router';
import { Pressable, StyleSheet, Text, View } from 'react-native';
import Svg, { Circle, Ellipse, Path } from 'react-native-svg';
import { Screen } from '@/components/screen';
import { asset } from '@/lib/assets';
const accent = '#E2475A';
const matches = [
{ a1: 'HB', c1: '#1F5FBF', t1: 'HBH', s1: '135', a2: 'RC', c2: '#D2362F', t2: 'RDC', s2: '129' },
{ a1: 'MV', c1: '#5B3FC4', t1: 'MTV', s1: '142', a2: 'BT', c2: '#0F7A6B', t2: 'BYT', s2: '128' },
];
export default function EventScreen() {
return (
<Screen background="#FFFFFF" statusBar="dark">
<View style={{ flex: 1 }}>
<LinearGradient
colors={['#F8B29A', '#F39A86', '#E26472', '#C2304A', '#A11F37']}
locations={[0, 0.32, 0.62, 0.85, 1]}
start={{ x: 0.5, y: 0 }}
end={{ x: 0.5, y: 1 }}
style={StyleSheet.absoluteFill}
/>
<View
style={{
position: 'absolute',
left: 20,
right: 20,
top: 58,
alignItems: 'center',
justifyContent: 'space-between',
flexDirection: 'row',
}}>
<Image
source={{ uri: asset('749545fb3c.jpg') }}
contentFit="cover"
accessibilityLabel="Your profile"
style={{
width: 46,
height: 46,
borderRadius: 23,
borderWidth: 2,
borderColor: '#FFFFFF',
}}
/>
<Text
style={{
flexShrink: 1,
fontFamily: 'Poppins_600SemiBold',
fontSize: 16,
color: '#2A0D10',
}}>
Event
</Text>
<Pressable
accessibilityRole="button"
accessibilityLabel="Open menu"
style={{
width: 46,
height: 46,
borderRadius: 23,
borderWidth: 0,
backgroundColor: '#1E0B0E',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="#FFFFFF"
strokeWidth="1.8"
strokeLinecap="round">
<Path d="M5 7h14" />
<Path d="M8 12h11" />
<Path d="M11 17h8" />
</Svg>
</Pressable>
</View>
<View style={{ position: 'absolute', left: 20, top: 128 }}>
<Text
style={{
fontFamily: 'Exo2_500Medium',
fontSize: 46,
color: '#2A0D10',
letterSpacing: -0.5,
lineHeight: 49.68,
}}>
Catch Every
</Text>
<Text
style={{
fontFamily: 'Exo2_500Medium',
fontSize: 46,
color: '#2A0D10',
letterSpacing: -0.5,
lineHeight: 49.68,
}}>
Game
</Text>
</View>
<Image
source={{ uri: asset('62c94f616b.png') }}
contentFit="cover"
contentPosition="top center"
accessibilityLabel="Player in a red #7 jersey holding a basketball"
style={{ position: 'absolute', right: 4, top: 96, width: 160, height: 200 }}
/>
<View
style={{
position: 'absolute',
left: 20,
right: 20,
top: 286,
flexDirection: 'row',
gap: 12,
}}>
<View
style={{
height: 168,
borderRadius: 22,
backgroundColor: '#1E0B0E',
padding: 12,
justifyContent: 'space-between',
flex: 1,
}}>
<View style={{ alignItems: 'center', gap: 10, flexDirection: 'row' }}>
<View
style={{
width: 44,
height: 44,
borderRadius: 22,
backgroundColor: '#2E1418',
alignItems: 'center',
justifyContent: 'center',
flexShrink: 0,
flexDirection: 'row',
}}>
<Svg width="24" height="24" viewBox="0 0 24 24">
<Circle cx="12" cy="12" r="10" fill="#F07A2E" />
<Path
d="M2 12h20M12 2v20M5 5c3 3 3 11 0 14M19 5c-3 3-3 11 0 14"
fill="none"
stroke="#3A1405"
strokeWidth="1.2"
/>
</Svg>
</View>
<Text
style={{
flexShrink: 1,
fontFamily: 'Poppins_400Regular',
fontSize: 13,
color: '#FFFFFF',
lineHeight: 17.55,
}}>
Complete Game Stats
</Text>
</View>
<View style={{ gap: 8, flexDirection: 'row' }}>
<View
style={{
flex: 1,
borderRadius: 14,
backgroundColor: '#2E1418',
paddingVertical: 8,
paddingHorizontal: 10,
}}>
<View style={{ alignItems: 'center', gap: 4, flexDirection: 'row' }}>
<Svg width="12" height="12" viewBox="0 0 24 24" fill="#FFC24A">
<Path d="M12 2l3 6.6 7 .8-5.2 4.8 1.4 7L12 17.8 5.8 21.2l1.4-7L2 9.4l7-.8z" />
</Svg>
<Text
style={{
fontFamily: 'Poppins_600SemiBold',
fontSize: 13,
color: '#FFFFFF',
flexShrink: 1,
}}>
1650
</Text>
</View>
<Text
style={{
fontFamily: 'Poppins_400Regular',
fontSize: 10,
color: 'rgba(255,255,255,0.7)',
}}>
Player Points
</Text>
</View>
<Pressable
accessibilityRole="button"
accessibilityLabel="Open game stats"
style={{
width: 44,
borderRadius: 14,
borderWidth: 0,
backgroundColor: '#2E1418',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="#FFFFFF"
strokeWidth="1.8"
strokeLinecap="round">
<Path d="M7 17L17 7M9 7h8v8" />
</Svg>
</Pressable>
</View>
</View>
<View
style={{
height: 168,
borderRadius: 22,
backgroundColor: '#1E0B0E',
padding: 14,
justifyContent: 'space-between',
flex: 1,
}}>
<Text
style={{
fontFamily: 'Poppins_400Regular',
fontSize: 13,
color: '#FFFFFF',
lineHeight: 17.55,
}}>
Completed{'\n'}Matches
</Text>
<View
style={{
alignItems: 'flex-end',
justifyContent: 'space-between',
flexDirection: 'row',
}}>
<Text
style={{
flexShrink: 1,
fontFamily: 'Exo2_500Medium',
fontSize: 44,
color: '#FFFFFF',
lineHeight: 44,
}}>
72
</Text>
<View style={{ width: 58, height: 58 }}>
<Svg width="58" height="58" viewBox="0 0 58 58">
<Circle cx="29" cy="29" r="24" fill="none" stroke="#3A1A1E" strokeWidth="5" />
<Circle
cx="29"
cy="29"
r="24"
fill="none"
stroke={accent}
strokeWidth="5"
strokeLinecap="round"
strokeDasharray="135.7 150.8"
transform="rotate(-90 29 29)"
/>
</Svg>
<View
style={{
position: 'absolute',
left: 0,
top: 0,
width: 58,
height: 58,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Text
style={{
fontFamily: 'Poppins_600SemiBold',
fontSize: 12,
color: '#FFFFFF',
flexShrink: 1,
}}>
90%
</Text>
</View>
</View>
</View>
</View>
</View>
<Text
style={{
position: 'absolute',
left: 20,
top: 478,
fontFamily: 'Poppins_500Medium',
fontSize: 14,
color: '#FFFFFF',
}}>
Sports
</Text>
<View
style={{
position: 'absolute',
left: 20,
right: 0,
top: 508,
gap: 10,
alignItems: 'center',
flexDirection: 'row',
}}>
<Pressable
accessibilityRole="button"
accessibilityLabel="Football"
style={{
width: 46,
height: 46,
borderRadius: 23,
borderWidth: 0,
backgroundColor: 'rgba(30,11,14,0.55)',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="22"
height="22"
viewBox="0 0 24 24"
fill="none"
stroke="#F3C34A"
strokeWidth="1.6">
<Ellipse cx="12" cy="12" rx="10" ry="6" transform="rotate(-40 12 12)" />
<Path d="M9 15l6-6M10 11l3 3M12 9l3 3" />
</Svg>
</Pressable>
<Pressable
accessibilityRole="button"
style={{
height: 46,
borderRadius: 23,
borderWidth: 0,
backgroundColor: '#1E0B0E',
alignItems: 'center',
gap: 10,
paddingVertical: 0,
paddingLeft: 6,
paddingRight: 18,
flexShrink: 1,
flexDirection: 'row',
}}>
<View
style={{
width: 34,
height: 34,
borderRadius: 17,
backgroundColor: '#2E1418',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg width="20" height="20" viewBox="0 0 24 24">
<Circle cx="12" cy="12" r="10" fill="#F07A2E" />
<Path
d="M2 12h20M12 2v20M5 5c3 3 3 11 0 14M19 5c-3 3-3 11 0 14"
fill="none"
stroke="#3A1405"
strokeWidth="1.2"
/>
</Svg>
</View>
<Text
style={{
fontFamily: 'Poppins_600SemiBold',
fontSize: 13,
color: '#FFFFFF',
flexShrink: 1,
}}>
Basketball
</Text>
</Pressable>
<Pressable
accessibilityRole="button"
accessibilityLabel="Volleyball"
style={{
width: 46,
height: 46,
borderRadius: 23,
borderWidth: 0,
backgroundColor: 'rgba(30,11,14,0.55)',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="22"
height="22"
viewBox="0 0 24 24"
fill="none"
stroke="#B9A7FF"
strokeWidth="1.6">
<Circle cx="12" cy="12" r="10" />
<Path d="M12 2c0 6 4 9 9 11M3 8c5 1 9 5 9 14M5 19c4-5 10-6 15-5" />
</Svg>
</Pressable>
<Pressable
accessibilityRole="button"
accessibilityLabel="Tennis"
style={{
width: 46,
height: 46,
borderRadius: 23,
borderWidth: 0,
backgroundColor: 'rgba(30,11,14,0.55)',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="22"
height="22"
viewBox="0 0 24 24"
fill="none"
stroke="#9BE37A"
strokeWidth="1.6">
<Circle cx="12" cy="12" r="10" />
<Path d="M5 5c4 4 4 10 0 14M19 5c-4 4-4 10 0 14" />
</Svg>
</Pressable>
<Pressable
accessibilityRole="button"
accessibilityLabel="Cricket"
style={{
width: 46,
height: 46,
borderRadius: 23,
borderWidth: 0,
backgroundColor: 'rgba(30,11,14,0.55)',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="22"
height="22"
viewBox="0 0 24 24"
fill="none"
stroke="#FF9AA8"
strokeWidth="1.6"
strokeLinecap="round">
<Path d="M4 20l9-9 3 3-9 9z" />
<Path d="M14 10l5-5" />
<Circle cx="18" cy="17" r="2.5" />
</Svg>
</Pressable>
</View>
<View
style={{
position: 'absolute',
left: 20,
right: 20,
top: 576,
alignItems: 'center',
justifyContent: 'space-between',
flexDirection: 'row',
}}>
<Text
style={{
flexShrink: 1,
fontFamily: 'Poppins_500Medium',
fontSize: 14,
color: '#FFFFFF',
}}>
Live Matches
</Text>
<View style={{ gap: 5, alignItems: 'center', flexShrink: 1, flexDirection: 'row' }}>
<View
style={{
width: 5,
height: 5,
borderRadius: 3,
backgroundColor: 'rgba(255,255,255,0.5)',
}}
/>
<View style={{ width: 14, height: 5, borderRadius: 3, backgroundColor: '#FFFFFF' }} />
<View
style={{
width: 5,
height: 5,
borderRadius: 3,
backgroundColor: 'rgba(255,255,255,0.5)',
}}
/>
</View>
</View>
<View
style={{
position: 'absolute',
left: 20,
right: 20,
top: 604,
flexDirection: 'row',
gap: 12,
flexWrap: 'wrap',
}}>
{matches.map((m, index) => (
<View
key={index}
style={{
borderRadius: 20,
backgroundColor: '#1E0B0E',
paddingVertical: 12,
paddingHorizontal: 14,
flexGrow: 1,
flexBasis: '34%',
}}>
<View
style={{
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: 10,
flexDirection: 'row',
}}>
<View
style={{
width: 34,
height: 34,
borderRadius: 17,
backgroundColor: m.c1,
alignItems: 'center',
justifyContent: 'center',
boxShadow: 'inset 0 0 0 2px rgba(255,255,255,0.85)',
flexDirection: 'row',
}}>
<Text
style={{
fontFamily: 'Exo2_700Bold',
fontSize: 11,
color: '#FFFFFF',
flexShrink: 1,
}}>
{m.a1}
</Text>
</View>
<Text
style={{
flexShrink: 1,
fontFamily: 'Poppins_600SemiBold',
fontSize: 13,
color: '#FFFFFF',
}}>
VS
</Text>
<View
style={{
width: 34,
height: 34,
borderRadius: 17,
backgroundColor: m.c2,
alignItems: 'center',
justifyContent: 'center',
boxShadow: 'inset 0 0 0 2px rgba(255,255,255,0.85)',
flexDirection: 'row',
}}>
<Text
style={{
fontFamily: 'Exo2_700Bold',
fontSize: 11,
color: '#FFFFFF',
flexShrink: 1,
}}>
{m.a2}
</Text>
</View>
</View>
<View style={{ justifyContent: 'space-between', flexDirection: 'row' }}>
<Text
style={{
flexShrink: 1,
fontFamily: 'Poppins_400Regular',
fontSize: 12,
color: 'rgba(255,255,255,0.75)',
lineHeight: 20.4,
}}>
{m.t1}
</Text>
<Text
style={{
flexShrink: 1,
fontFamily: 'Poppins_600SemiBold',
fontSize: 12,
color: '#FFFFFF',
lineHeight: 20.4,
}}>
{m.s1}
</Text>
</View>
<View style={{ justifyContent: 'space-between', flexDirection: 'row' }}>
<Text
style={{
flexShrink: 1,
fontFamily: 'Poppins_400Regular',
fontSize: 12,
color: 'rgba(255,255,255,0.75)',
lineHeight: 20.4,
}}>
{m.t2}
</Text>
<Text
style={{
flexShrink: 1,
fontFamily: 'Poppins_600SemiBold',
fontSize: 12,
color: '#FFFFFF',
lineHeight: 20.4,
}}>
{m.s2}
</Text>
</View>
</View>
))}
</View>
<View
style={{
position: 'absolute',
left: 32,
right: 32,
bottom: 30,
height: 64,
borderRadius: 32,
backgroundColor: '#1E0B0E',
alignItems: 'center',
justifyContent: 'space-around',
paddingVertical: 0,
paddingHorizontal: 6,
boxShadow: '0 12px 30px rgba(60,5,15,0.4)',
flexDirection: 'row',
}}>
<Pressable
accessibilityRole="link"
accessibilityLabel="Home"
onPress={() => router.navigate('/event')}
style={{
width: 44,
height: 44,
borderRadius: 22,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="22"
height="22"
viewBox="0 0 24 24"
fill="none"
stroke="#FFFFFF"
strokeWidth="1.7"
strokeLinejoin="round">
<Path d="M4 10l8-6 8 6v9a1 1 0 0 1-1 1h-4v-6H9v6H5a1 1 0 0 1-1-1z" />
</Svg>
</Pressable>
<Pressable
accessibilityRole="link"
accessibilityLabel="Search"
onPress={() => router.navigate('/event')}
style={{
width: 44,
height: 44,
borderRadius: 22,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="22"
height="22"
viewBox="0 0 24 24"
fill="none"
stroke="#FFFFFF"
strokeWidth="1.7"
strokeLinecap="round">
<Circle cx="11" cy="11" r="7" />
<Path d="M20 20l-4-4" />
</Svg>
</Pressable>
<Pressable
accessibilityRole="link"
accessibilityLabel="Favorites"
onPress={() => router.navigate('/event')}
style={{
width: 52,
height: 52,
borderRadius: 26,
backgroundColor: accent,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="22"
height="22"
viewBox="0 0 24 24"
fill="none"
stroke="#FFFFFF"
strokeWidth="1.7"
strokeLinejoin="round">
<Path d="M12 3l2.7 5.8 6.3.7-4.7 4.3 1.3 6.2L12 17l-5.6 3 1.3-6.2L3 9.5l6.3-.7z" />
</Svg>
</Pressable>
<Pressable
accessibilityRole="link"
accessibilityLabel="Live streams"
onPress={() => router.navigate('/streams')}
style={{
width: 44,
height: 44,
borderRadius: 22,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="22"
height="22"
viewBox="0 0 24 24"
fill="none"
stroke="#FFFFFF"
strokeWidth="1.7"
strokeLinecap="round">
<Circle cx="12" cy="12" r="2" />
<Path d="M8.5 8.5a5 5 0 0 0 0 7M15.5 8.5a5 5 0 0 1 0 7M5.6 5.6a9 9 0 0 0 0 12.8M18.4 5.6a9 9 0 0 1 0 12.8" />
</Svg>
</Pressable>
<Pressable
accessibilityRole="link"
accessibilityLabel="Profile"
onPress={() => router.navigate('/event')}
style={{
width: 44,
height: 44,
borderRadius: 22,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="22"
height="22"
viewBox="0 0 24 24"
fill="none"
stroke="#FFFFFF"
strokeWidth="1.7"
strokeLinecap="round">
<Circle cx="12" cy="8" r="4" />
<Path d="M4 21c1.5-4 4.5-6 8-6s6.5 2 8 6" />
</Svg>
</Pressable>
</View>
</View>
</Screen>
);
}src/app/streams.tsx
import { Image } from 'expo-image';
import { LinearGradient } from 'expo-linear-gradient';
import { router } from 'expo-router';
import { Pressable, StyleSheet, Text, View } from 'react-native';
import Svg, { Circle, Path } from 'react-native-svg';
import { Screen } from '@/components/screen';
import { asset } from '@/lib/assets';
const accent = '#E2475A';
const stats = [
{ label: 'Field Goals Attempt', value: '96 / 101', indent: 0, bg: '#1E0B0E', red: 10, green: 14 },
{
label: 'Field Goals Made',
value: '42 / 43',
indent: 14,
bg: 'rgba(110,15,30,0.55)',
red: 8,
green: 16,
},
{ label: 'Total Field Goals %', value: '45 / 41', indent: 0, bg: '#1E0B0E', red: 14, green: 10 },
{
label: 'Total Team Assists',
value: '36 / 32',
indent: 14,
bg: 'rgba(110,15,30,0.55)',
red: 12,
green: 12,
},
];
export default function StreamsScreen() {
return (
<Screen background="#FFFFFF" statusBar="dark">
<View style={{ flex: 1 }}>
<LinearGradient
colors={['#F8B29A', '#F39A86', '#E26472', '#C2304A', '#A11F37']}
locations={[0, 0.3, 0.58, 0.82, 1]}
start={{ x: 0.5, y: 0 }}
end={{ x: 0.5, y: 1 }}
style={StyleSheet.absoluteFill}
/>
<View
style={{
position: 'absolute',
left: 20,
right: 20,
top: 58,
alignItems: 'center',
justifyContent: 'space-between',
flexDirection: 'row',
}}>
<Image
source={{ uri: asset('749545fb3c.jpg') }}
contentFit="cover"
accessibilityLabel="Your profile"
style={{
width: 46,
height: 46,
borderRadius: 23,
borderWidth: 2,
borderColor: '#FFFFFF',
}}
/>
<Text
style={{
flexShrink: 1,
fontFamily: 'Poppins_600SemiBold',
fontSize: 16,
color: '#2A0D10',
}}>
Streams
</Text>
<Pressable
accessibilityRole="button"
accessibilityLabel="Notifications"
style={{
width: 46,
height: 46,
borderRadius: 23,
borderWidth: 0,
backgroundColor: '#1E0B0E',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="#FFFFFF"
strokeWidth="1.8"
strokeLinecap="round"
strokeLinejoin="round">
<Path d="M6 16V11a6 6 0 0 1 12 0v5l2 2H4z" />
<Path d="M10 21h4" />
</Svg>
</Pressable>
</View>
<View
style={{
position: 'absolute',
left: 20,
right: 20,
top: 126,
borderRadius: 24,
backgroundColor: '#1E0B0E',
padding: 14,
}}>
<View
style={{
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: 12,
flexDirection: 'row',
}}>
<View style={{ alignItems: 'center', gap: 6, flexShrink: 1, flexDirection: 'row' }}>
<View style={{ width: 7, height: 7, borderRadius: 4, backgroundColor: '#FF5A6E' }} />
<Text
style={{
fontFamily: 'Poppins_600SemiBold',
fontSize: 15,
color: '#FF5A6E',
flexShrink: 1,
}}>
Live
</Text>
</View>
<View
style={{
alignItems: 'center',
gap: 8,
backgroundColor: '#2E1418',
borderRadius: 14,
paddingVertical: 6,
paddingLeft: 8,
paddingRight: 12,
flexShrink: 1,
flexDirection: 'row',
}}>
<Svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="#FFFFFF"
strokeWidth="1.7"
strokeLinecap="round">
<Circle cx="12" cy="12" r="9" />
<Path d="M12 7v5l3 2" />
</Svg>
<Text
style={{
fontFamily: 'Poppins_400Regular',
fontSize: 11,
color: '#FFFFFF',
flexShrink: 1,
}}>
08:30:22 PM
</Text>
</View>
</View>
<View style={{ alignItems: 'center', gap: 10, flexDirection: 'row' }}>
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'space-between',
backgroundColor: '#2E1418',
borderRadius: 16,
paddingVertical: 10,
paddingHorizontal: 14,
flexDirection: 'row',
}}>
<View
style={{
width: 38,
height: 38,
borderRadius: 19,
backgroundColor: '#5B3FC4',
alignItems: 'center',
justifyContent: 'center',
boxShadow: 'inset 0 0 0 2px rgba(255,255,255,0.85)',
flexDirection: 'row',
}}>
<Text
style={{
fontFamily: 'Exo2_700Bold',
fontSize: 12,
color: '#FFFFFF',
flexShrink: 1,
}}>
MV
</Text>
</View>
<Text
style={{
flexShrink: 1,
fontFamily: 'Exo2_600SemiBold',
fontSize: 24,
color: '#FFFFFF',
}}>
142
</Text>
</View>
<Text
style={{
flexShrink: 1,
fontFamily: 'Poppins_600SemiBold',
fontSize: 14,
color: '#FFFFFF',
}}>
VS
</Text>
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'space-between',
backgroundColor: '#2E1418',
borderRadius: 16,
paddingVertical: 10,
paddingHorizontal: 14,
flexDirection: 'row',
}}>
<Text
style={{
flexShrink: 1,
fontFamily: 'Exo2_600SemiBold',
fontSize: 24,
color: '#FFFFFF',
}}>
128
</Text>
<View
style={{
width: 38,
height: 38,
borderRadius: 19,
backgroundColor: '#0F7A6B',
alignItems: 'center',
justifyContent: 'center',
boxShadow: 'inset 0 0 0 2px rgba(255,255,255,0.85)',
flexDirection: 'row',
}}>
<Text
style={{
fontFamily: 'Exo2_700Bold',
fontSize: 12,
color: '#FFFFFF',
flexShrink: 1,
}}>
BT
</Text>
</View>
</View>
</View>
<View style={{ justifyContent: 'space-between', marginTop: 10, flexDirection: 'row' }}>
<Text
style={{
flexShrink: 1,
fontFamily: 'Poppins_600SemiBold',
fontSize: 13,
color: '#FFFFFF',
}}>
MTV
</Text>
<Text
style={{
flexShrink: 1,
fontFamily: 'Poppins_600SemiBold',
fontSize: 13,
color: '#FFFFFF',
}}>
BYT
</Text>
</View>
</View>
<View style={{ position: 'absolute', left: 20, right: 20, top: 330, gap: 10 }}>
{stats.map((s, index) => (
<View
key={index}
style={{
alignItems: 'center',
justifyContent: 'space-between',
flexDirection: 'row',
}}>
<View
style={{
marginLeft: s.indent,
width: 152,
height: 58,
borderRadius: 16,
backgroundColor: s.bg,
paddingVertical: 0,
paddingLeft: 14,
paddingRight: 10,
alignItems: 'center',
justifyContent: 'space-between',
gap: 8,
flexDirection: 'row',
}}>
<Text
style={{
flexShrink: 1,
fontFamily: 'Poppins_400Regular',
fontSize: 12,
color: '#FFFFFF',
lineHeight: 16.2,
}}>
{s.label}
</Text>
<View style={{ gap: 3, flexShrink: 1 }}>
<View
style={{ width: 5, height: s.red, borderRadius: 3, backgroundColor: '#FF5A6E' }}
/>
<View
style={{
width: 5,
height: s.green,
borderRadius: 3,
backgroundColor: '#4ADE80',
}}
/>
</View>
</View>
<View
style={{
width: 92,
height: 58,
borderRadius: 16,
backgroundColor: 'rgba(110,15,30,0.45)',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Text
style={{
fontFamily: 'Poppins_600SemiBold',
fontSize: 13,
color: '#FFFFFF',
flexShrink: 1,
}}>
{s.value}
</Text>
</View>
</View>
))}
</View>
<View
style={{
position: 'absolute',
left: 20,
right: 20,
top: 604,
height: 240,
borderRadius: 26,
overflow: 'hidden',
}}>
<LinearGradient
colors={['#3A1218', '#1E0B0E']}
locations={[0, 1]}
start={{ x: 0.329, y: 0.03 }}
end={{ x: 0.671, y: 0.97 }}
style={StyleSheet.absoluteFill}
/>
<Image
source={{ uri: asset('d3d8973874.jpg') }}
contentFit="cover"
contentPosition={{ left: '60%', top: '20%' }}
accessibilityLabel="Live stream: player dunking at the hoop"
style={{ position: 'absolute', left: 0, top: 0, width: '100%', height: '100%' }}
/>
<Text
style={{
position: 'absolute',
right: 16,
top: 18,
backgroundColor: 'rgba(30,11,14,0.7)',
borderRadius: 12,
paddingVertical: 4,
paddingHorizontal: 12,
fontFamily: 'Poppins_600SemiBold',
fontSize: 11,
color: '#FFFFFF',
}}>
Live
</Text>
</View>
<View
style={{
position: 'absolute',
left: 32,
right: 32,
bottom: 30,
height: 64,
borderRadius: 32,
backgroundColor: 'rgba(30,11,14,0.92)',
alignItems: 'center',
justifyContent: 'space-around',
paddingVertical: 0,
paddingHorizontal: 6,
boxShadow: '0 12px 30px rgba(60,5,15,0.4)',
flexDirection: 'row',
}}>
<Pressable
accessibilityRole="link"
accessibilityLabel="Home"
onPress={() => router.navigate('/event')}
style={{
width: 44,
height: 44,
borderRadius: 22,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="22"
height="22"
viewBox="0 0 24 24"
fill="none"
stroke="#FFFFFF"
strokeWidth="1.7"
strokeLinejoin="round">
<Path d="M4 10l8-6 8 6v9a1 1 0 0 1-1 1h-4v-6H9v6H5a1 1 0 0 1-1-1z" />
</Svg>
</Pressable>
<Pressable
accessibilityRole="link"
accessibilityLabel="Search"
onPress={() => router.navigate('/event')}
style={{
width: 44,
height: 44,
borderRadius: 22,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="22"
height="22"
viewBox="0 0 24 24"
fill="none"
stroke="#FFFFFF"
strokeWidth="1.7"
strokeLinecap="round">
<Circle cx="11" cy="11" r="7" />
<Path d="M20 20l-4-4" />
</Svg>
</Pressable>
<Pressable
accessibilityRole="link"
accessibilityLabel="Favorites"
onPress={() => router.navigate('/event')}
style={{
width: 44,
height: 44,
borderRadius: 22,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="22"
height="22"
viewBox="0 0 24 24"
fill="none"
stroke="#FFFFFF"
strokeWidth="1.7"
strokeLinejoin="round">
<Path d="M12 3l2.7 5.8 6.3.7-4.7 4.3 1.3 6.2L12 17l-5.6 3 1.3-6.2L3 9.5l6.3-.7z" />
</Svg>
</Pressable>
<Pressable
accessibilityRole="link"
accessibilityLabel="Live streams"
onPress={() => router.navigate('/streams')}
style={{
width: 52,
height: 52,
borderRadius: 26,
backgroundColor: accent,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="22"
height="22"
viewBox="0 0 24 24"
fill="none"
stroke="#FFFFFF"
strokeWidth="1.7"
strokeLinecap="round">
<Circle cx="12" cy="12" r="2" />
<Path d="M8.5 8.5a5 5 0 0 0 0 7M15.5 8.5a5 5 0 0 1 0 7M5.6 5.6a9 9 0 0 0 0 12.8M18.4 5.6a9 9 0 0 1 0 12.8" />
</Svg>
</Pressable>
<Pressable
accessibilityRole="link"
accessibilityLabel="Profile"
onPress={() => router.navigate('/event')}
style={{
width: 44,
height: 44,
borderRadius: 22,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="22"
height="22"
viewBox="0 0 24 24"
fill="none"
stroke="#FFFFFF"
strokeWidth="1.7"
strokeLinecap="round">
<Circle cx="12" cy="8" r="4" />
<Path d="M4 21c1.5-4 4.5-6 8-6s6.5 2 8 6" />
</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 wide artboard, then scaled to the device width.
const ARTBOARD_WIDTH = 390;
type Props = {
background: string;
statusBar: 'light' | 'dark';
height?: number;
children: ReactNode;
};
export function Screen({ background, statusBar, height: artboardHeight = 844, 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(artboardHeight * scale, height) }}>
<StatusBar style={statusBar} />
<View
style={{
width: ARTBOARD_WIDTH,
height: artboardHeight,
overflow: 'hidden',
transformOrigin: 'left top',
transform: [{ scale }],
}}>
{children}
</View>
</ScrollView>
);
}src/lib/assets.ts
// Demo images are hosted by DeveloperMill. Point this at your own CDN, or swap to require().
const ASSET_BASE = 'https://developermill.com/app-designs/basketball-tickets-app-ui-design/assets';
export const asset = (name: string) => `${ASSET_BASE}/${name}`;About this design
Coral gradients and dark panels keep the numbers readable. The stat comparison bars and live match cards are flexible, so the layout also suits a fantasy sports, ticketing or fan engagement app.
Coral to crimson gradients with sporty italic numbers, dark rounded stat panels and a cut-out player leading each screen.
- Season countdown hero with a player cut-out
- Sport picker and live match cards
- Team comparison rows for field goals and assists
- Coral gradient backgrounds with dark stat panels
Colour palette
Crimson
#C21F3A
Rose
#E2475A
Coral
#F07A5E
Blush
#FFE3E6
Oxblood
#2A0D10
Night
#1E0B0E
How to use this design
- 01
Pick what to copy
Copy the Courtside Basketball 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
Can I show real game data?
Yes. Scores, stats and team names are plain values on each screen, so a sports API can replace them without layout changes.
How are the gradients built?
Backgrounds use expo-linear-gradient, and the stat rings and bars use react-native-svg and simple views.
Is it only for basketball?
No. The sport picker is already in the event screen. Change the player photos and stat labels for football, hockey or tennis.
Is the Courtside Basketball 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.



