// Sports app UI
Live Football Scores App UI Design in Expo
This live football scores app UI gives a match day a stadium feel. A glowing player hero opens the app, angled scorecards fill the live screen, and a full pitch shows the starting eleven.
- Screens
- 3
- Built with
- Expo SDK 58
- Fonts
- Manrope
- License
- Free (MIT)

Live Football Scores app screens

Onboarding
A large headline, a framed player photo on a red glow, a team follow card and a Let's Go slide control.

Live matches
A league card with a progress ring, then angled live cards showing scores, odds and team tabs.

Starting lineup
A match countdown above a green pitch with player photos in formation and a curved tab selector.
Copy the Live Football Scores 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
# Live Football Scores: design artifact
This live football scores app UI gives a match day a stadium feel. A glowing player hero opens the app, angled scorecards fill the live screen, and a full pitch shows the starting eleven.
- Type: Sports mobile app UI
- Screens: 3
- Artboard: 390 × 844
- Target: Expo SDK 58, Expo Router, TypeScript, expo-blur, expo-image, expo-linear-gradient, react-native-svg
- Live page: https://developermill.com/app-designs/live-football-scores-app-ui-design
## Design direction
Dark ember backgrounds with a red to amber glow, angled match cards and a bright green pitch that breaks up the dark screens.
- Glowing onboarding with a slide action
- Angled live match cards with odds
- Starting eleven drawn on a full pitch
- Curved tab bar with text on an SVG path
## Foundations
### Colour
| Token | Hex |
| --- | --- |
| Ember black | `#120807` |
| Smoke | `#2A1712` |
| Live red | `#FF3B2F` |
| Amber | `#FFB020` |
| Soft gold | `#FFD27A` |
| White | `#FFFFFF` |
### Typography
- Typefaces: Manrope
- Common sizes (px): 9, 12, 13, 14, 15, 16, 17, 46
### Shape and depth
- Common corner radii (px): 12, 14, 22, 23, 26, 30
- Shadows: `0 4px 10px rgba(0,0,0,0.25)`, `0 6px 18px rgba(0,0,0,0.3)`
## Screens
### 1. Onboarding
A large headline, a framed player photo on a red glow, a team follow card and a Let's Go slide control.
Preview: https://developermill.com/app-designs/live-football-scores-app-ui-design/welcome.webp
Copy on this screen:
- Live Scores
- Made Simple
- Follow Your Favorite Teams
- Track match results and team updates easily
- Let's Go
### 2. Live matches
A league card with a progress ring, then angled live cards showing scores, odds and team tabs.
Preview: https://developermill.com/app-designs/live-football-scores-app-ui-design/match.webp
Copy on this screen:
- Football
- 24 Sep
- Live
- Continental League
- Round 8
- Live Match
- Northport FC
- Vale City
- 4 : 1
- Northport
- Statistics
- 1.03
- 16.07
- 8.78
- Aurora United
- Redcliffe
- 3 : 0
### 3. Starting lineup
A match countdown above a green pitch with player photos in formation and a curved tab selector.
Preview: https://developermill.com/app-designs/live-football-scores-app-ui-design/lineup.webp
Copy on this screen:
- Match Today
- 07:32:59
- 22:00
- Aurora United
- Redcliffe
- Aurora United · Starting XI
## Full source
The original artboards as HTML. Image URLs point at the hosted demo assets.
### Onboarding (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=Manrope:wght@400;500;600;700;800&display=swap">
<style>
body{margin:0}
a{color:#ffb020}a:hover{color:#ffd27a}
</style>
</helmet>
<div style="width: 390px; height: 844px; box-sizing: border-box; padding: 64px 24px 32px; display: flex; flex-direction: column; gap: 28px; font-family: Manrope, system-ui, sans-serif; color: #ffffff; background: radial-gradient(120% 60% at 20% 0%, #5a1a12 0%, #2a0f0c 45%, #120807 100%); overflow: hidden">
<div style="display: flex; align-items: flex-start; justify-content: space-between; gap: 12px">
<h1 style="margin: 0; font-size: 42px; line-height: 1.1; font-weight: 700; letter-spacing: -0.5px">Live Scores<br>Made Simple</h1>
<div style="width: 52px; height: 52px; border-radius: 26px; background: rgba(255,255,255,0.14); display: flex; align-items: center; justify-content: center; flex-shrink: 0; margin-top: 4px">
<svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"></circle><path d="M12 7l4 3-1.5 4.5h-5L8 10z"></path><path d="M12 3v4M21 10.5l-5 -0.5M17.5 19l-3-4.5M6.5 19l3-4.5M3 10.5l5-0.5"></path></svg>
</div>
</div>
<div style="flex-grow: 1; position: relative; border-radius: 32px; overflow: hidden; background: linear-gradient(180deg, #3a1712 0%, #2a120e 100%); border: 1px solid rgba(255,255,255,0.08)">
<div aria-hidden="true" style="position: absolute; left: -40px; top: 120px; width: 220px; height: 220px; border-radius: 110px; background: #d4231a; filter: blur(70px); opacity: 0.75"></div>
<div aria-hidden="true" style="position: absolute; right: -50px; top: 40px; width: 200px; height: 200px; border-radius: 100px; background: #f2b81c; filter: blur(70px); opacity: 0.6"></div>
<img src="https://developermill.com/app-designs/live-football-scores-app-ui-design/assets/45709a4745.jpg" alt="Footballer in a sky-blue kit dribbling a ball" style="position: absolute; left: 0; top: 0; width: 100%; height: 100%; object-fit: cover; object-position: center 20%">
<div aria-hidden="true" style="position: absolute; left: 0; right: 0; bottom: 0; height: 200px; background: linear-gradient(180deg, rgba(26,10,8,0) 0%, rgba(26,10,8,0.85) 100%)"></div>
<div style="position: absolute; left: 14px; right: 14px; bottom: 14px; border-radius: 22px; padding: 16px; background: rgba(120,70,40,0.55); backdrop-filter: blur(14px); display: flex; gap: 14px; align-items: center">
<div style="width: 48px; height: 48px; border-radius: 24px; background: rgba(255,255,255,0.12); display: flex; align-items: center; justify-content: center; flex-shrink: 0">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 21h8M12 17v4M7 4h10v5a5 5 0 0 1-10 0z"></path><path d="M17 5h3v2a3 3 0 0 1-3 3M7 5H4v2a3 3 0 0 0 3 3"></path></svg>
</div>
<div style="display: flex; flex-direction: column; gap: 4px">
<span style="font-size: 16px; font-weight: 700">Follow Your Favorite Teams</span>
<span style="font-size: 13px; line-height: 1.4; color: rgba(255,255,255,0.78)">Track match results and team updates easily</span>
</div>
</div>
</div>
<div style="display: flex; gap: 12px; align-items: center">
<button aria-label="Back" style="width: 56px; height: 56px; border-radius: 28px; border: none; background: rgba(255,255,255,0.1); display: flex; align-items: center; justify-content: center; flex-shrink: 0; cursor: pointer">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 18l-6-6 6-6"></path></svg>
</button>
<a href="Match.dc.html" style="flex-grow: 1; height: 56px; border-radius: 28px; background: rgba(255,255,255,0.1); display: flex; align-items: center; justify-content: space-between; padding: 0 6px 0 24px; text-decoration: none; color: #ffffff">
<span style="font-size: 17px; font-weight: 600">Let's Go</span>
<span style="display: flex; align-items: center; gap: 10px">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="rgba(255,255,255,0.45)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 17l5-5-5-5M13 17l5-5-5-5"></path></svg>
<span style="width: 46px; height: 46px; border-radius: 23px; background: linear-gradient(135deg, #ff3b2f, #ffb020); display: flex; align-items: center; justify-content: center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"></circle><path d="M12 7l4 3-1.5 4.5h-5L8 10z"></path></svg>
</span>
</span>
</a>
</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>
```
### Live matches (Match)
```html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Live Matches</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&display=swap">
<style>
body{margin:0}
a{color:#ffb020}a:hover{color:#ffd27a}
</style>
</helmet>
<div style="width: 390px; height: 844px; box-sizing: border-box; padding: 56px 16px 0; display: flex; flex-direction: column; gap: 14px; font-family: Manrope, system-ui, sans-serif; color: #ffffff; background: #150a08; overflow: hidden">
<div style="display: flex; align-items: center; gap: 10px">
<div style="flex-grow: 1; height: 60px; border-radius: 30px; background: #2a1712; display: flex; align-items: center; gap: 14px; padding: 0 8px">
<a href="Main.dc.html" aria-label="Back" style="width: 44px; height: 44px; border-radius: 22px; background: rgba(255,255,255,0.08); display: flex; align-items: center; justify-content: center">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 18l-6-6 6-6"></path></svg>
</a>
<div style="display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 16px; font-weight: 700">Football</span>
<span style="font-size: 12px; color: rgba(255,255,255,0.7)">24 Sep</span>
</div>
</div>
<button style="width: 60px; height: 60px; border-radius: 30px; border: none; background: #3a120e; color: #ff5a4a; font-family: inherit; font-size: 13px; font-weight: 700; cursor: pointer">Live</button>
<button aria-label="Standings" style="width: 60px; height: 60px; border-radius: 30px; border: none; background: #2a1712; display: flex; align-items: center; justify-content: center; cursor: pointer">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 21h8M12 17v4M7 4h10v5a5 5 0 0 1-10 0z"></path></svg>
</button>
</div>
<div style="position: relative; border-radius: 28px; padding: 18px 18px 26px; background: linear-gradient(180deg, #3a1d16 0%, #22110d 100%); display: flex; flex-direction: column; align-items: center; gap: 12px">
<div style="display: flex; flex-direction: column; align-items: center; gap: 2px">
<span style="font-size: 15px; font-weight: 700">Continental League</span>
<span style="font-size: 12px; color: rgba(255,255,255,0.7)">Round 8</span>
</div>
<div style="width: 100%; display: flex; align-items: center; justify-content: space-between">
<div style="width: 52px; height: 52px; border-radius: 26px; background: rgba(255,255,255,0.08); display: flex; align-items: center; justify-content: center">
<svg width="26" height="26" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="10" fill="#2f6bff"></circle><path d="M12 2a10 10 0 0 1 10 10H12z" fill="#ff3b2f"></path><path d="M2 12A10 10 0 0 0 12 22V12z" fill="#ffb020"></path><circle cx="12" cy="12" r="4" fill="#ffffff"></circle></svg>
</div>
<div style="width: 84px; height: 84px; border-radius: 42px; background: conic-gradient(#ff3b2f 0deg, #ffb020 200deg, rgba(255,255,255,0.08) 200deg); display: flex; align-items: center; justify-content: center">
<div style="width: 70px; height: 70px; border-radius: 35px; background: #22110d; display: flex; align-items: center; justify-content: center">
<svg width="34" height="34" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" role="img" aria-label="League emblem"><path d="M12 3l7 3v5c0 4.5-3 8-7 10-4-2-7-5.5-7-10V6z"></path><path d="M9 11l2 2 4-4"></path></svg>
</div>
</div>
<div style="width: 52px; height: 52px; border-radius: 26px; background: rgba(255,255,255,0.08); display: flex; align-items: center; justify-content: center">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="14" cy="4" r="2"></circle><path d="M13 7l-3 5 3 2-1 6M10 12l-4 2M13 14l5 1"></path><circle cx="19" cy="19" r="2"></circle></svg>
</div>
</div>
</div>
<div style="margin-top: 14px; position: relative; border-radius: 30px; padding: 10px; background: linear-gradient(180deg, #a86c22 0%, #5e3714 15%, #2a160c 30%, #2a160c 100%)">
<svg width="358" height="24" viewBox="0 0 358 24" aria-hidden="true" style="position: absolute; left: 0; top: -23px; overflow: visible"><path d="M70 24 C90 24 92 2 112 1 H246 C266 2 268 24 288 24 Z" fill="#a86c22"></path></svg>
<div aria-hidden="true" style="position: absolute; z-index: 1; left: 50%; top: 24px; width: 150px; height: 18px; margin-left: -75px; border-radius: 50%; background: rgba(0,0,0,0.75); filter: blur(7px)"></div>
<button style="position: absolute; z-index: 2; left: 50%; top: -14px; transform: translateX(-50%); width: 158px; height: 46px; padding: 0; border: none; background: linear-gradient(90deg, #ff2f2f 0%, #ff7a1f 55%, #ffc21a 100%); clip-path: polygon(4% 0, 96% 0, 100% 18%, 100% 45%, 92% 100%, 8% 100%, 0 45%, 0 18%); color: #ffffff; font-family: inherit; font-size: 14px; font-weight: 600; cursor: pointer">Live Match</button>
<div style="position: relative; box-sizing: border-box; border-radius: 22px; padding: 38px 12px 12px; background: linear-gradient(180deg, #1c0e0a 0%, #1c0e0a 50%, #3e2110 100%); display: flex; flex-direction: column; gap: 14px">
<div style="display: flex; align-items: center; justify-content: space-between">
<div style="display: flex; align-items: center; gap: 10px">
<div style="width: 44px; height: 44px; border-radius: 22px; background: rgba(255,255,255,0.08); display: flex; align-items: center; justify-content: center">
<svg width="26" height="26" viewBox="0 0 24 24" role="img" aria-label="Northport FC crest"><path d="M12 2l8 3v6c0 5-3.5 9-8 11-4.5-2-8-6-8-11V5z" fill="#1e3a8a"></path><path d="M12 2v20c-4.5-2-8-6-8-11V5z" fill="#b91c1c"></path><text x="12" y="15" text-anchor="middle" font-size="7" font-weight="800" fill="#ffd34d" font-family="Manrope, sans-serif">NP</text></svg>
</div>
<span style="font-size: 14px; font-weight: 600">Northport FC</span>
</div>
<div style="display: flex; align-items: center; gap: 10px">
<span style="font-size: 14px; font-weight: 600">Vale City</span>
<div style="width: 44px; height: 44px; border-radius: 22px; background: rgba(255,255,255,0.08); display: flex; align-items: center; justify-content: center">
<svg width="26" height="26" viewBox="0 0 24 24" role="img" aria-label="Vale City crest"><circle cx="12" cy="12" r="10" fill="#f59e0b"></circle><circle cx="12" cy="12" r="7" fill="#111111"></circle><text x="12" y="14.5" text-anchor="middle" font-size="7" font-weight="800" fill="#f59e0b" font-family="Manrope, sans-serif">VC</text></svg>
</div>
</div>
</div>
<div style="text-align: center; font-size: 46px; font-weight: 700; letter-spacing: 2px; margin: -4px 0 2px">4 : 1</div>
<div style="display: flex; gap: 8px">
<button style="flex: 1 1 0; height: 46px; border-radius: 14px; border: 1px solid rgba(255,255,255,0.12); background: rgba(255,255,255,0.06); color: #ffffff; font-family: inherit; font-size: 13px; font-weight: 600; display: flex; align-items: center; justify-content: center; gap: 8px; cursor: pointer">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="18" height="16" rx="3"></rect><path d="M8 3v4M16 3v4M3 10h18"></path></svg>Northport
</button>
<button style="flex: 1 1 0; height: 46px; border-radius: 14px; border: 1px solid rgba(255,255,255,0.12); background: rgba(255,255,255,0.06); color: #ffffff; font-family: inherit; font-size: 13px; font-weight: 600; display: flex; align-items: center; justify-content: center; gap: 8px; cursor: pointer">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12A9 9 0 1 1 12 3v9z"></path><path d="M15 3.5A9 9 0 0 1 20.5 9H15z"></path></svg>Statistics
</button>
<button aria-label="Save match" style="width: 46px; height: 46px; border-radius: 14px; border: 1px solid rgba(255,255,255,0.12); background: rgba(255,255,255,0.06); display: flex; align-items: center; justify-content: center; cursor: pointer">
<svg width="16" height="16" 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 3h12v18l-6-4-6 4z"></path></svg>
</button>
</div>
<div style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px">
<div style="height: 42px; border-radius: 12px; background: #3a1a12; border: 1px solid rgba(255,120,60,0.25); display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 600">1.03</div>
<div style="height: 42px; border-radius: 12px; background: #3a1a12; border: 1px solid rgba(255,120,60,0.25); display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 600">16.07</div>
<div style="height: 42px; border-radius: 12px; background: #3a1a12; border: 1px solid rgba(255,120,60,0.25); display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 600">8.78</div>
</div>
</div>
</div>
<div style="margin-top: 30px; position: relative; border-radius: 30px; padding: 8px; background: #2a1611">
<svg width="358" height="24" viewBox="0 0 358 24" aria-hidden="true" style="position: absolute; left: 0; top: -23px; overflow: visible"><path d="M70 24 C90 24 92 2 112 1 H246 C266 2 268 24 288 24 Z" fill="#2a1611"></path></svg>
<div aria-hidden="true" style="position: absolute; z-index: 1; left: 50%; top: 24px; width: 150px; height: 18px; margin-left: -75px; border-radius: 50%; background: rgba(0,0,0,0.75); filter: blur(7px)"></div>
<button style="position: absolute; z-index: 2; left: 50%; top: -14px; transform: translateX(-50%); width: 158px; height: 46px; padding: 0; border: none; background: linear-gradient(90deg, #ff2f2f 0%, #ff7a1f 55%, #ffc21a 100%); clip-path: polygon(4% 0, 96% 0, 100% 18%, 100% 45%, 92% 100%, 8% 100%, 0 45%, 0 18%); color: #ffffff; font-family: inherit; font-size: 14px; font-weight: 600; cursor: pointer">Live Match</button>
<a href="Lineup.dc.html" style="box-sizing: border-box; border-radius: 22px; padding: 38px 12px 24px; background: #190c09; display: flex; flex-direction: column; gap: 6px; text-decoration: none; color: #ffffff">
<div style="display: flex; align-items: center; justify-content: space-between">
<div style="display: flex; align-items: center; gap: 10px">
<div style="width: 44px; height: 44px; border-radius: 22px; background: rgba(255,255,255,0.08); display: flex; align-items: center; justify-content: center">
<svg width="26" height="26" viewBox="0 0 24 24" role="img" aria-label="Aurora United crest"><circle cx="12" cy="12" r="10" fill="#ffffff"></circle><path d="M5 15l7-10 7 10z" fill="#6d28d9"></path><circle cx="12" cy="12" r="10" fill="none" stroke="#d4af37" stroke-width="1.5"></circle></svg>
</div>
<span style="font-size: 14px; font-weight: 600">Aurora United</span>
</div>
<div style="display: flex; align-items: center; gap: 10px">
<span style="font-size: 14px; font-weight: 600">Redcliffe</span>
<div style="width: 44px; height: 44px; border-radius: 22px; background: #ffffff; display: flex; align-items: center; justify-content: center">
<svg width="26" height="26" viewBox="0 0 24 24" role="img" aria-label="Redcliffe crest"><circle cx="12" cy="12" r="10" fill="#dc2626"></circle><path d="M7 16l5-9 5 9z" fill="#ffffff"></path></svg>
</div>
</div>
</div>
<div style="text-align: center; font-size: 46px; font-weight: 700; letter-spacing: 2px">3 : 0</div>
</a>
</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>
```
### Starting lineup (Lineup)
```html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Match Lineup</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&display=swap">
<style>
body{margin:0}
a{color:#ffb020}a:hover{color:#ffd27a}
</style>
</helmet>
<div style="width: 390px; height: 844px; display: flex; flex-direction: column; font-family: Manrope, system-ui, sans-serif; color: #ffffff; background: #120807; overflow: hidden">
<div style="padding: 56px 16px 18px; display: flex; flex-direction: column; gap: 14px; background: #120807">
<div style="display: flex; align-items: center; justify-content: space-between">
<a href="Match.dc.html" aria-label="Back" style="width: 46px; height: 46px; border-radius: 23px; background: rgba(255,255,255,0.08); display: flex; align-items: center; justify-content: center">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 18l-6-6 6-6"></path></svg>
</a>
<span style="font-size: 16px; font-weight: 600">Match Today</span>
<button aria-label="Favourite match" style="width: 46px; height: 46px; border-radius: 23px; border: none; background: rgba(255,255,255,0.08); 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="M12 3l2.8 5.7 6.2.9-4.5 4.4 1 6.2L12 17.3 6.5 20.2l1-6.2L3 9.6l6.2-.9z"></path></svg>
</button>
</div>
<div style="display: flex; flex-direction: column; align-items: center; gap: 2px">
<span style="font-size: 40px; font-weight: 700; letter-spacing: 1px">07:32:59</span>
<span style="font-size: 13px; color: rgba(255,255,255,0.7)">22:00</span>
</div>
<div style="display: flex; align-items: center; justify-content: space-between">
<div style="display: flex; align-items: center; gap: 10px">
<div style="width: 44px; height: 44px; border-radius: 22px; background: rgba(255,255,255,0.08); display: flex; align-items: center; justify-content: center">
<svg width="26" height="26" viewBox="0 0 24 24" role="img" aria-label="Aurora United crest"><circle cx="12" cy="12" r="10" fill="#ffffff"></circle><path d="M5 15l7-10 7 10z" fill="#6d28d9"></path><circle cx="12" cy="12" r="10" fill="none" stroke="#d4af37" stroke-width="1.5"></circle></svg>
</div>
<span style="font-size: 14px; font-weight: 600">Aurora United</span>
</div>
<div style="display: flex; align-items: center; gap: 10px">
<span style="font-size: 14px; font-weight: 600">Redcliffe</span>
<div style="width: 44px; height: 44px; border-radius: 22px; background: #ffffff; display: flex; align-items: center; justify-content: center">
<svg width="26" height="26" viewBox="0 0 24 24" role="img" aria-label="Redcliffe crest"><circle cx="12" cy="12" r="10" fill="#dc2626"></circle><path d="M7 16l5-9 5 9z" fill="#ffffff"></path></svg>
</div>
</div>
</div>
</div>
<div style="flex-grow: 1; position: relative; border-radius: 32px 32px 0 0; overflow: hidden; background: repeating-linear-gradient(180deg, #3f9f3a 0px, #3f9f3a 48px, #378f33 48px, #378f33 96px)">
<div aria-hidden="true" style="position: absolute; left: 20px; right: 20px; top: 128px; height: 0; border-top: 2px solid rgba(255,255,255,0.55)"></div>
<div aria-hidden="true" style="position: absolute; left: 135px; top: 68px; width: 120px; height: 120px; border-radius: 60px; border: 2px solid rgba(255,255,255,0.55); box-sizing: border-box"></div>
<div aria-hidden="true" style="position: absolute; left: 20px; right: 20px; bottom: 96px; height: 0; border-top: 2px solid rgba(255,255,255,0.55)"></div>
<div aria-hidden="true" style="position: absolute; left: 105px; bottom: -2px; width: 180px; height: 34px; border: 2px solid rgba(255,255,255,0.55); border-bottom: none; box-sizing: border-box"></div>
<span style="position: absolute; left: 0; right: 0; top: 18px; text-align: center; font-size: 13px; font-weight: 700; color: #ffffff">Aurora United · Starting XI</span>
<sc-for list="{{players}}" as="p" hint-placeholder-count="11">
<div style="{{p.pos}}">
<div style="position: relative; width: 46px; height: 46px">
<img src="{{p.img}}" alt="{{p.alt}}" style="display: block; width: 46px; height: 46px; box-sizing: border-box; border-radius: 23px; border: 2.5px solid #ffffff; object-fit: cover; background: #cfcfcf; box-shadow: 0 4px 10px rgba(0,0,0,0.25)">
<span style="position: absolute; left: -14px; top: 12px; min-width: 22px; height: 16px; padding: 0 4px; box-sizing: border-box; border-radius: 8px; background: #111111; color: #ffffff; font-size: 9px; font-weight: 700; display: flex; align-items: center; justify-content: center">{{p.num}}</span>
</div>
<span aria-hidden="true" style="width: 2px; height: 20px; background: rgba(255,255,255,0.9)"></span>
<span aria-hidden="true" style="width: 6px; height: 6px; border-radius: 3px; background: #ffffff"></span>
</div>
</sc-for>
<div style="position: absolute; left: 75px; bottom: 0; width: 240px; height: 170px">
<svg width="240" height="170" viewBox="0 0 240 170" role="img" aria-label="Match tabs: Overview, Match, Line-Up (selected), H2H" style="position: absolute; left: 0; top: 0; overflow: visible">
<defs><path id="tabArc" d="M35 162.8 A88 88 0 1 1 205 162.8"></path></defs>
<use href="#tabArc" fill="none" stroke="rgba(12,70,24,0.6)" stroke-width="30" stroke-linecap="round"></use>
<use href="#tabArc" fill="none" stroke="#ffffff" stroke-width="28" stroke-linecap="round" stroke-dasharray="66 1000" stroke-dashoffset="-190"></use>
<text font-family="Manrope, sans-serif" font-size="11" font-weight="600" fill="#ffffff" dominant-baseline="middle"><textPath href="#tabArc" startOffset="16%" text-anchor="middle">Overview</textPath></text>
<text font-family="Manrope, sans-serif" font-size="11" font-weight="600" fill="#ffffff" dominant-baseline="middle"><textPath href="#tabArc" startOffset="42%" text-anchor="middle">Match</textPath></text>
<text font-family="Manrope, sans-serif" font-size="11" font-weight="700" fill="#1d1d1d" dominant-baseline="middle"><textPath href="#tabArc" startOffset="69%" text-anchor="middle">Line-Up</textPath></text>
<text font-family="Manrope, sans-serif" font-size="11" font-weight="600" fill="#ffffff" dominant-baseline="middle"><textPath href="#tabArc" startOffset="93%" text-anchor="middle">H2H</textPath></text>
</svg>
<button aria-label="Match centre" style="position: absolute; left: 86px; top: 106px; width: 68px; height: 68px; border-radius: 34px; border: none; background: #ffffff; display: flex; align-items: center; justify-content: center; box-shadow: 0 6px 18px rgba(0,0,0,0.3); cursor: pointer">
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#1d1d1d" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"></circle><path d="M12 7l4 3-1.5 4.5h-5L8 10z"></path><path d="M12 3v4M21 10.5l-5-0.5M17.5 19l-3-4.5M6.5 19l3-4.5M3 10.5l5-0.5"></path></svg>
</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() {
const xi = [
[42, 60, 11, 'Mensah', 'e6fec6ff908fc0ed66f7a5512387a4c3'],
[172, 44, 9, 'Ricci', 'af6cadb70842e7b9f8849f2e7143d4a8'],
[302, 60, 7, 'Haddad', 'a8b3b873ae7ebdd88a9050a260db7cd1'],
[36, 180, 14, 'Kovač', '28f4ccdb4692f63e8046d6a7b320f077'],
[172, 168, 8, 'Sato', '44b3f3ee572f5992116d1740381b106e'],
[308, 180, 10, 'Boateng', '55e8e9bac9b1e744c097a47a2cd6a016'],
[24, 290, 3, 'Lindqvist', '6c12f3b1353d15ab68910e3040bf13e6'],
[118, 272, 4, 'Durand', 'a297ae3265b90e914973445da438d450'],
[226, 272, 5, 'Varga', '416415b6bb6159293306e94b426b3cae'],
[320, 290, 2, 'Nowak', '6816eb6b590b087ad600a3cc9d27beb5'],
[172, 330, 1, 'Moreno', '4ad77ac073bce745659fb8bb3b42afa7']
];
return {
players: xi.map(([x, y, num, name, id]) => ({
num, name,
img: '/_blob/' + id,
alt: '#' + num + ' ' + name,
pos: 'position: absolute; left: ' + (x - 6) + 'px; top: ' + y + 'px; width: 58px; display: flex; flex-direction: column; align-items: center'
}))
};
}
}
</script>
</body>
</html>
```SKILL.md
Save as .claude/skills/live-football-scores-app-ui/SKILL.md
--- name: live-football-scores-app-ui description: Build the Live Football Scores mobile app UI in Expo React Native. Use when asked to create a football score app UI or a new screen in this visual style. --- # Live Football Scores app UI Build this sports app UI in an Expo Router project with TypeScript. Reference: https://developermill.com/app-designs/live-football-scores-app-ui-design ## Visual direction Dark ember backgrounds with a red to amber glow, angled match cards and a bright green pitch that breaks up the dark screens. Keep these signature details: - Glowing onboarding with a slide action - Angled live match cards with odds - Starting eleven drawn on a full pitch - Curved tab bar with text on an SVG path ## Set up ```bash npx expo install expo-blur expo-image expo-linear-gradient react-native-svg @expo-google-fonts/manrope expo-font ``` ## Tokens | Name | Hex | | --- | --- | | Ember black | `#120807` | | Smoke | `#2A1712` | | Live red | `#FF3B2F` | | Amber | `#FFB020` | | Soft gold | `#FFD27A` | | White | `#FFFFFF` | - Typefaces: Manrope - Text sizes (px): 9, 12, 13, 14, 15, 16, 17, 46 - Corner radii (px): 12, 14, 22, 23, 26, 30 Define these once and reuse them. Do not add new colours. ## Screens 1. **Onboarding.** A large headline, a framed player photo on a red glow, a team follow card and a Let's Go slide control. 2. **Live matches.** A league card with a progress ring, then angled live cards showing scores, odds and team tabs. 3. **Starting lineup.** A match countdown above a green pitch with player photos in formation and a curved tab selector. ## 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 live-football-scores-app --template default cd live-football-scores-app rm -rf src npx expo install expo-blur expo-image expo-linear-gradient react-native-svg @expo-google-fonts/manrope expo-font
src/app/_layout.tsx
import {
Manrope_400Regular,
Manrope_600SemiBold,
Manrope_700Bold,
Manrope_800ExtraBold,
} from '@expo-google-fonts/manrope';
import { useFonts } from 'expo-font';
import { Stack } from 'expo-router';
export default function RootLayout() {
const [fontsLoaded] = useFonts({
Manrope_400Regular,
Manrope_600SemiBold,
Manrope_700Bold,
Manrope_800ExtraBold,
});
if (!fontsLoaded) return null;
return <Stack screenOptions={{ headerShown: false }} />;
}src/app/index.tsx
import { BlurView } from 'expo-blur';
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, Defs, Path, RadialGradient, Rect, Stop } from 'react-native-svg';
import { Screen } from '@/components/screen';
import { asset } from '@/lib/assets';
export default function MainScreen() {
return (
<Screen background="#FFFFFF" statusBar="dark">
<View style={{ paddingTop: 64, paddingBottom: 32, paddingHorizontal: 24, gap: 28, flex: 1 }}>
<Svg style={StyleSheet.absoluteFill} width="100%" height="100%">
<Defs>
<RadialGradient id="glow1" cx="20%" cy="0%" rx="120%" ry="60%" fx="20%" fy="0%">
<Stop offset="0%" stopColor="#5a1a12" />
<Stop offset="45%" stopColor="#2a0f0c" />
<Stop offset="100%" stopColor="#120807" />
</RadialGradient>
</Defs>
<Rect width="100%" height="100%" fill="url(#glow1)" />
</Svg>
<View
style={{
alignItems: 'flex-start',
justifyContent: 'space-between',
gap: 12,
flexDirection: 'row',
}}>
<Text
style={{
margin: 0,
flexShrink: 1,
fontFamily: 'Manrope_700Bold',
fontSize: 42,
color: '#ffffff',
letterSpacing: -0.5,
lineHeight: 46.2,
}}>
Live Scores{'\n'}Made Simple
</Text>
<View
style={{
width: 52,
height: 52,
borderRadius: 26,
backgroundColor: 'rgba(255,255,255,0.14)',
alignItems: 'center',
justifyContent: 'center',
flexShrink: 0,
marginTop: 4,
flexDirection: 'row',
}}>
<Svg
width="26"
height="26"
viewBox="0 0 24 24"
fill="none"
stroke="#ffffff"
strokeWidth="1.6"
strokeLinecap="round"
strokeLinejoin="round">
<Circle cx="12" cy="12" r="9" />
<Path d="M12 7l4 3-1.5 4.5h-5L8 10z" />
<Path d="M12 3v4M21 10.5l-5 -0.5M17.5 19l-3-4.5M6.5 19l3-4.5M3 10.5l5-0.5" />
</Svg>
</View>
</View>
<View
style={{
flexGrow: 1,
borderRadius: 32,
overflow: 'hidden',
borderWidth: 1,
borderColor: 'rgba(255,255,255,0.08)',
}}>
<LinearGradient
colors={['#3a1712', '#2a120e']}
locations={[0, 1]}
start={{ x: 0.5, y: 0 }}
end={{ x: 0.5, y: 1 }}
style={StyleSheet.absoluteFill}
/>
<View
style={{
position: 'absolute',
left: -40,
top: 120,
width: 220,
height: 220,
borderRadius: 110,
backgroundColor: '#d4231a',
filter: 'blur(70px)',
opacity: 0.75,
}}
/>
<View
style={{
position: 'absolute',
right: -50,
top: 40,
width: 200,
height: 200,
borderRadius: 100,
backgroundColor: '#f2b81c',
filter: 'blur(70px)',
opacity: 0.6,
}}
/>
<Image
source={{ uri: asset('45709a4745.jpg') }}
contentFit="cover"
contentPosition={{ left: 'center', top: '20%' }}
accessibilityLabel="Footballer in a sky-blue kit dribbling a ball"
style={{ position: 'absolute', left: 0, top: 0, width: '100%', height: '100%' }}
/>
<View style={{ position: 'absolute', left: 0, right: 0, bottom: 0, height: 200 }}>
<LinearGradient
colors={['rgba(26,10,8,0)', 'rgba(26,10,8,0.85)']}
locations={[0, 1]}
start={{ x: 0.5, y: 0 }}
end={{ x: 0.5, y: 1 }}
style={StyleSheet.absoluteFill}
/>
</View>
<View
style={{
position: 'absolute',
left: 14,
right: 14,
bottom: 14,
borderRadius: 22,
padding: 16,
backgroundColor: 'rgba(120,70,40,0.55)',
gap: 14,
alignItems: 'center',
overflow: 'hidden',
flexDirection: 'row',
}}>
<BlurView intensity={28} tint="default" style={StyleSheet.absoluteFill} />
<View
style={{
width: 48,
height: 48,
borderRadius: 24,
backgroundColor: 'rgba(255,255,255,0.12)',
alignItems: 'center',
justifyContent: 'center',
flexShrink: 0,
flexDirection: 'row',
}}>
<Svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="#ffffff"
strokeWidth="1.6"
strokeLinecap="round"
strokeLinejoin="round">
<Path d="M8 21h8M12 17v4M7 4h10v5a5 5 0 0 1-10 0z" />
<Path d="M17 5h3v2a3 3 0 0 1-3 3M7 5H4v2a3 3 0 0 0 3 3" />
</Svg>
</View>
<View style={{ gap: 4, flexShrink: 1 }}>
<Text style={{ fontFamily: 'Manrope_700Bold', fontSize: 16, color: '#ffffff' }}>
Follow Your Favorite Teams
</Text>
<Text
style={{
fontFamily: 'Manrope_400Regular',
fontSize: 13,
color: 'rgba(255,255,255,0.78)',
lineHeight: 18.2,
}}>
Track match results and team updates easily
</Text>
</View>
</View>
</View>
<View style={{ gap: 12, alignItems: 'center', flexDirection: 'row' }}>
<Pressable
accessibilityRole="button"
accessibilityLabel="Back"
style={{
width: 56,
height: 56,
borderRadius: 28,
borderWidth: 0,
backgroundColor: 'rgba(255,255,255,0.1)',
alignItems: 'center',
justifyContent: 'center',
flexShrink: 0,
flexDirection: 'row',
}}>
<Svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="#ffffff"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round">
<Path d="M15 18l-6-6 6-6" />
</Svg>
</Pressable>
<Pressable
accessibilityRole="link"
onPress={() => router.navigate('/match')}
style={{
flexGrow: 1,
height: 56,
borderRadius: 28,
backgroundColor: 'rgba(255,255,255,0.1)',
alignItems: 'center',
justifyContent: 'space-between',
paddingVertical: 0,
paddingLeft: 24,
paddingRight: 6,
flexShrink: 1,
flexDirection: 'row',
}}>
<Text
style={{
flexShrink: 1,
fontFamily: 'Manrope_600SemiBold',
fontSize: 17,
color: '#ffffff',
}}>
{"Let's Go"}
</Text>
<View style={{ alignItems: 'center', gap: 10, flexShrink: 1, flexDirection: 'row' }}>
<Svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="rgba(255,255,255,0.45)"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round">
<Path d="M6 17l5-5-5-5M13 17l5-5-5-5" />
</Svg>
<View
style={{
width: 46,
height: 46,
borderRadius: 23,
alignItems: 'center',
justifyContent: 'center',
overflow: 'hidden',
flexDirection: 'row',
}}>
<LinearGradient
colors={['#ff3b2f', '#ffb020']}
locations={[0, 1]}
start={{ x: 0.146, y: 0.146 }}
end={{ x: 0.854, y: 0.854 }}
style={StyleSheet.absoluteFill}
/>
<Svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="#ffffff"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
style={{ position: 'relative' }}>
<Circle cx="12" cy="12" r="9" />
<Path d="M12 7l4 3-1.5 4.5h-5L8 10z" />
</Svg>
</View>
</View>
</Pressable>
</View>
</View>
</Screen>
);
}src/app/lineup.tsx
import { Image } from 'expo-image';
import { router } from 'expo-router';
import { Pressable, Text, View } from 'react-native';
import Svg, { Circle, Defs, Path, TextPath, Use, Text as SvgText } from 'react-native-svg';
import { Screen } from '@/components/screen';
import { Stripes } from '@/components/stripes';
import { asset } from '@/lib/assets';
import { css, cssText } from '@/lib/css';
const players = [
{
num: 11,
name: 'Mensah',
img: 'e6fec6ff90.jpg',
alt: '#11 Mensah',
pos: 'position: absolute; left: 36px; top: 60px; width: 58px; display: flex; flex-direction: column; align-items: center',
},
{
num: 9,
name: 'Ricci',
img: 'af6cadb708.jpg',
alt: '#9 Ricci',
pos: 'position: absolute; left: 166px; top: 44px; width: 58px; display: flex; flex-direction: column; align-items: center',
},
{
num: 7,
name: 'Haddad',
img: 'a8b3b873ae.jpg',
alt: '#7 Haddad',
pos: 'position: absolute; left: 296px; top: 60px; width: 58px; display: flex; flex-direction: column; align-items: center',
},
{
num: 14,
name: 'Kovač',
img: '28f4ccdb46.jpg',
alt: '#14 Kovač',
pos: 'position: absolute; left: 30px; top: 180px; width: 58px; display: flex; flex-direction: column; align-items: center',
},
{
num: 8,
name: 'Sato',
img: '44b3f3ee57.jpg',
alt: '#8 Sato',
pos: 'position: absolute; left: 166px; top: 168px; width: 58px; display: flex; flex-direction: column; align-items: center',
},
{
num: 10,
name: 'Boateng',
img: '55e8e9bac9.jpg',
alt: '#10 Boateng',
pos: 'position: absolute; left: 302px; top: 180px; width: 58px; display: flex; flex-direction: column; align-items: center',
},
{
num: 3,
name: 'Lindqvist',
img: '6c12f3b135.jpg',
alt: '#3 Lindqvist',
pos: 'position: absolute; left: 18px; top: 290px; width: 58px; display: flex; flex-direction: column; align-items: center',
},
{
num: 4,
name: 'Durand',
img: 'a297ae3265.jpg',
alt: '#4 Durand',
pos: 'position: absolute; left: 112px; top: 272px; width: 58px; display: flex; flex-direction: column; align-items: center',
},
{
num: 5,
name: 'Varga',
img: '416415b6bb.jpg',
alt: '#5 Varga',
pos: 'position: absolute; left: 220px; top: 272px; width: 58px; display: flex; flex-direction: column; align-items: center',
},
{
num: 2,
name: 'Nowak',
img: '6816eb6b59.jpg',
alt: '#2 Nowak',
pos: 'position: absolute; left: 314px; top: 290px; width: 58px; display: flex; flex-direction: column; align-items: center',
},
{
num: 1,
name: 'Moreno',
img: '4ad77ac073.jpg',
alt: '#1 Moreno',
pos: 'position: absolute; left: 166px; top: 330px; width: 58px; display: flex; flex-direction: column; align-items: center',
},
];
export default function LineupScreen() {
return (
<Screen background="#120807" statusBar="light">
<View style={{ flex: 1 }}>
<View
style={{
paddingTop: 56,
paddingBottom: 18,
paddingHorizontal: 16,
gap: 14,
backgroundColor: '#120807',
}}>
<View
style={{ alignItems: 'center', justifyContent: 'space-between', flexDirection: 'row' }}>
<Pressable
accessibilityRole="link"
accessibilityLabel="Back"
onPress={() => router.navigate('/match')}
style={{
width: 46,
height: 46,
borderRadius: 23,
backgroundColor: 'rgba(255,255,255,0.08)',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="#ffffff"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round">
<Path d="M15 18l-6-6 6-6" />
</Svg>
</Pressable>
<Text
style={{
flexShrink: 1,
fontFamily: 'Manrope_600SemiBold',
fontSize: 16,
color: '#ffffff',
}}>
Match Today
</Text>
<Pressable
accessibilityRole="button"
accessibilityLabel="Favourite match"
style={{
width: 46,
height: 46,
borderRadius: 23,
borderWidth: 0,
backgroundColor: 'rgba(255,255,255,0.08)',
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="M12 3l2.8 5.7 6.2.9-4.5 4.4 1 6.2L12 17.3 6.5 20.2l1-6.2L3 9.6l6.2-.9z" />
</Svg>
</Pressable>
</View>
<View style={{ alignItems: 'center', gap: 2 }}>
<Text
style={{
fontFamily: 'Manrope_700Bold',
fontSize: 40,
color: '#ffffff',
letterSpacing: 1,
}}>
07:32:59
</Text>
<Text
style={{
fontFamily: 'Manrope_400Regular',
fontSize: 13,
color: 'rgba(255,255,255,0.7)',
}}>
22:00
</Text>
</View>
<View
style={{ alignItems: 'center', justifyContent: 'space-between', flexDirection: 'row' }}>
<View style={{ alignItems: 'center', gap: 10, flexShrink: 1, flexDirection: 'row' }}>
<View
style={{
width: 44,
height: 44,
borderRadius: 22,
backgroundColor: 'rgba(255,255,255,0.08)',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="26"
height="26"
viewBox="0 0 24 24"
accessibilityRole="image"
accessibilityLabel="Aurora United crest">
<Circle cx="12" cy="12" r="10" fill="#ffffff" />
<Path d="M5 15l7-10 7 10z" fill="#6d28d9" />
<Circle cx="12" cy="12" r="10" fill="none" stroke="#d4af37" strokeWidth="1.5" />
</Svg>
</View>
<Text
style={{
flexShrink: 1,
fontFamily: 'Manrope_600SemiBold',
fontSize: 14,
color: '#ffffff',
}}>
Aurora United
</Text>
</View>
<View style={{ alignItems: 'center', gap: 10, flexShrink: 1, flexDirection: 'row' }}>
<Text
style={{
flexShrink: 1,
fontFamily: 'Manrope_600SemiBold',
fontSize: 14,
color: '#ffffff',
}}>
Redcliffe
</Text>
<View
style={{
width: 44,
height: 44,
borderRadius: 22,
backgroundColor: '#ffffff',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="26"
height="26"
viewBox="0 0 24 24"
accessibilityRole="image"
accessibilityLabel="Redcliffe crest">
<Circle cx="12" cy="12" r="10" fill="#dc2626" />
<Path d="M7 16l5-9 5 9z" fill="#ffffff" />
</Svg>
</View>
</View>
</View>
</View>
<View
style={{
flexGrow: 1,
borderTopLeftRadius: 32,
borderTopRightRadius: 32,
borderBottomRightRadius: 0,
borderBottomLeftRadius: 0,
overflow: 'hidden',
}}>
<Stripes first={'#3f9f3a'} second={'#378f33'} size={48} angle={180} />
<View
style={{
position: 'absolute',
left: 20,
right: 20,
top: 128,
height: 2,
borderTopWidth: 2,
borderTopColor: 'rgba(255,255,255,0.55)',
zIndex: 1,
}}
/>
<View
style={{
position: 'absolute',
left: 135,
top: 68,
width: 120,
height: 120,
borderRadius: 60,
borderWidth: 2,
borderColor: 'rgba(255,255,255,0.55)',
zIndex: 1,
}}
/>
<View
style={{
position: 'absolute',
left: 20,
right: 20,
bottom: 96,
height: 2,
borderTopWidth: 2,
borderTopColor: 'rgba(255,255,255,0.55)',
zIndex: 1,
}}
/>
<View
style={{
position: 'absolute',
left: 105,
bottom: -2,
width: 180,
height: 34,
borderWidth: 2,
borderColor: 'rgba(255,255,255,0.55)',
borderBottomWidth: 0,
zIndex: 1,
}}
/>
<Text
style={{
position: 'absolute',
left: 0,
right: 0,
top: 18,
zIndex: 1,
fontFamily: 'Manrope_700Bold',
fontSize: 13,
color: '#ffffff',
textAlign: 'center',
}}>
Aurora United · Starting XI
</Text>
{players.map((p, index) => (
<View key={index} style={{ ...css(p.pos) }}>
<View style={{ width: 46, height: 46 }}>
<Image
source={{ uri: asset(p.img) }}
contentFit="cover"
style={{
width: 46,
height: 46,
borderRadius: 23,
borderWidth: 2.5,
borderColor: '#ffffff',
backgroundColor: '#cfcfcf',
boxShadow: '0 4px 10px rgba(0,0,0,0.25)',
}}
/>
<View
style={{
position: 'absolute',
left: -14,
top: 12,
minWidth: 22,
height: 16,
paddingVertical: 0,
paddingHorizontal: 4,
borderRadius: 8,
backgroundColor: '#111111',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Text
style={[
{
fontFamily: 'Manrope_700Bold',
fontSize: 9,
color: '#ffffff',
flexShrink: 1,
},
cssText(p.pos),
]}>
{p.num}
</Text>
</View>
</View>
<View style={{ width: 2, height: 20, backgroundColor: 'rgba(255,255,255,0.9)' }} />
<View style={{ width: 6, height: 6, borderRadius: 3, backgroundColor: '#ffffff' }} />
</View>
))}
<View style={{ position: 'absolute', left: 75, bottom: 0, width: 240, height: 170 }}>
<Svg
width="240"
height="170"
viewBox="0 0 240 170"
accessibilityRole="image"
accessibilityLabel="Match tabs: Overview, Match, Line-Up (selected), H2H"
style={{ position: 'absolute', left: 0, top: 0 }}>
<Defs>
<Path id="tabArc" d="M35 162.8 A88 88 0 1 1 205 162.8" />
</Defs>
<Use
href="#tabArc"
fill="none"
stroke="rgba(12,70,24,0.6)"
strokeWidth="30"
strokeLinecap="round"
/>
<Use
href="#tabArc"
fill="none"
stroke="#ffffff"
strokeWidth="28"
strokeLinecap="round"
strokeDasharray="66 1000"
strokeDashoffset="-190"
/>
<SvgText
fontFamily="Manrope_600SemiBold"
fontSize="11"
fill="#ffffff"
alignmentBaseline="middle">
<TextPath href="#tabArc" startOffset="16%" textAnchor="middle">
Overview
</TextPath>
</SvgText>
<SvgText
fontFamily="Manrope_600SemiBold"
fontSize="11"
fill="#ffffff"
alignmentBaseline="middle">
<TextPath href="#tabArc" startOffset="42%" textAnchor="middle">
Match
</TextPath>
</SvgText>
<SvgText
fontFamily="Manrope_700Bold"
fontSize="11"
fill="#1d1d1d"
alignmentBaseline="middle">
<TextPath href="#tabArc" startOffset="69%" textAnchor="middle">
Line-Up
</TextPath>
</SvgText>
<SvgText
fontFamily="Manrope_600SemiBold"
fontSize="11"
fill="#ffffff"
alignmentBaseline="middle">
<TextPath href="#tabArc" startOffset="93%" textAnchor="middle">
H2H
</TextPath>
</SvgText>
</Svg>
<Pressable
accessibilityRole="button"
accessibilityLabel="Match centre"
style={{
position: 'absolute',
left: 86,
top: 106,
width: 68,
height: 68,
borderRadius: 34,
borderWidth: 0,
backgroundColor: '#ffffff',
alignItems: 'center',
justifyContent: 'center',
boxShadow: '0 6px 18px rgba(0,0,0,0.3)',
flexDirection: 'row',
}}>
<Svg
width="28"
height="28"
viewBox="0 0 24 24"
fill="none"
stroke="#1d1d1d"
strokeWidth="1.6"
strokeLinecap="round"
strokeLinejoin="round">
<Circle cx="12" cy="12" r="9" />
<Path d="M12 7l4 3-1.5 4.5h-5L8 10z" />
<Path d="M12 3v4M21 10.5l-5-0.5M17.5 19l-3-4.5M6.5 19l3-4.5M3 10.5l5-0.5" />
</Svg>
</Pressable>
</View>
</View>
</View>
</Screen>
);
}src/app/match.tsx
import { LinearGradient } from 'expo-linear-gradient';
import { router } from 'expo-router';
import { Pressable, StyleSheet, Text, View } from 'react-native';
import Svg, {
Circle,
Defs,
Path,
Polygon,
Rect,
Stop,
Text as SvgText,
LinearGradient as SvgLinearGradient,
} from 'react-native-svg';
import { Screen } from '@/components/screen';
export default function MatchScreen() {
return (
<Screen background="#150a08" statusBar="light">
<View style={{ paddingTop: 56, paddingBottom: 0, paddingHorizontal: 16, gap: 14, flex: 1 }}>
<View style={{ alignItems: 'center', gap: 10, flexDirection: 'row' }}>
<View
style={{
flexGrow: 1,
height: 60,
borderRadius: 30,
backgroundColor: '#2a1712',
alignItems: 'center',
gap: 14,
paddingVertical: 0,
paddingHorizontal: 8,
flexShrink: 1,
flexDirection: 'row',
}}>
<Pressable
accessibilityRole="link"
accessibilityLabel="Back"
onPress={() => router.navigate('/')}
style={{
width: 44,
height: 44,
borderRadius: 22,
backgroundColor: 'rgba(255,255,255,0.08)',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="#ffffff"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round">
<Path d="M15 18l-6-6 6-6" />
</Svg>
</Pressable>
<View style={{ gap: 2, flexShrink: 1 }}>
<Text style={{ fontFamily: 'Manrope_700Bold', fontSize: 16, color: '#ffffff' }}>
Football
</Text>
<Text
style={{
fontFamily: 'Manrope_400Regular',
fontSize: 12,
color: 'rgba(255,255,255,0.7)',
}}>
24 Sep
</Text>
</View>
</View>
<Pressable
accessibilityRole="button"
style={{
width: 60,
height: 60,
borderRadius: 30,
borderWidth: 0,
backgroundColor: '#3a120e',
alignItems: 'center',
justifyContent: 'center',
}}>
<Text
style={{
fontFamily: 'Manrope_700Bold',
fontSize: 13,
color: '#ff5a4a',
textAlign: 'center',
}}>
Live
</Text>
</Pressable>
<Pressable
accessibilityRole="button"
accessibilityLabel="Standings"
style={{
width: 60,
height: 60,
borderRadius: 30,
borderWidth: 0,
backgroundColor: '#2a1712',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="22"
height="22"
viewBox="0 0 24 24"
fill="none"
stroke="#ffffff"
strokeWidth="1.6"
strokeLinecap="round"
strokeLinejoin="round">
<Path d="M8 21h8M12 17v4M7 4h10v5a5 5 0 0 1-10 0z" />
</Svg>
</Pressable>
</View>
<View
style={{
borderRadius: 28,
paddingTop: 18,
paddingBottom: 26,
paddingHorizontal: 18,
alignItems: 'center',
gap: 12,
overflow: 'hidden',
}}>
<LinearGradient
colors={['#3a1d16', '#22110d']}
locations={[0, 1]}
start={{ x: 0.5, y: 0 }}
end={{ x: 0.5, y: 1 }}
style={StyleSheet.absoluteFill}
/>
<View style={{ alignItems: 'center', gap: 2 }}>
<Text style={{ fontFamily: 'Manrope_700Bold', fontSize: 15, color: '#ffffff' }}>
Continental League
</Text>
<Text
style={{
fontFamily: 'Manrope_400Regular',
fontSize: 12,
color: 'rgba(255,255,255,0.7)',
}}>
Round 8
</Text>
</View>
<View
style={{
width: '100%',
alignItems: 'center',
justifyContent: 'space-between',
flexDirection: 'row',
}}>
<View
style={{
width: 52,
height: 52,
borderRadius: 26,
backgroundColor: 'rgba(255,255,255,0.08)',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg width="26" height="26" viewBox="0 0 24 24">
<Circle cx="12" cy="12" r="10" fill="#2f6bff" />
<Path d="M12 2a10 10 0 0 1 10 10H12z" fill="#ff3b2f" />
<Path d="M2 12A10 10 0 0 0 12 22V12z" fill="#ffb020" />
<Circle cx="12" cy="12" r="4" fill="#ffffff" />
</Svg>
</View>
<View
style={{
width: 84,
height: 84,
borderRadius: 42,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="84"
height="84"
viewBox="0 0 84 84"
style={{ position: 'absolute', left: 0, top: 0, zIndex: 1 }}>
<Defs>
<SvgLinearGradient id="ringFill" x1="0" y1="0" x2="0" y2="1">
<Stop offset="0" stopColor="#ff3b2f" />
<Stop offset="1" stopColor="#ffb020" />
</SvgLinearGradient>
</Defs>
<Circle
cx="42"
cy="42"
r="38.5"
fill="none"
stroke="rgba(255,255,255,0.08)"
strokeWidth="7"
/>
<Path
d="M42 3.5 A38.5 38.5 0 1 1 28.8 78.2"
fill="none"
stroke="url(#ringFill)"
strokeWidth="7"
/>
</Svg>
<View
style={{
width: 70,
height: 70,
borderRadius: 35,
backgroundColor: '#22110d',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="34"
height="34"
viewBox="0 0 24 24"
fill="none"
stroke="#ffffff"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
accessibilityRole="image"
accessibilityLabel="League emblem">
<Path d="M12 3l7 3v5c0 4.5-3 8-7 10-4-2-7-5.5-7-10V6z" />
<Path d="M9 11l2 2 4-4" />
</Svg>
</View>
</View>
<View
style={{
width: 52,
height: 52,
borderRadius: 26,
backgroundColor: 'rgba(255,255,255,0.08)',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="#ffffff"
strokeWidth="1.6"
strokeLinecap="round"
strokeLinejoin="round">
<Circle cx="14" cy="4" r="2" />
<Path d="M13 7l-3 5 3 2-1 6M10 12l-4 2M13 14l5 1" />
<Circle cx="19" cy="19" r="2" />
</Svg>
</View>
</View>
</View>
<View style={{ marginTop: 14, borderRadius: 30, padding: 10, overflow: 'hidden' }}>
<LinearGradient
colors={['#a86c22', '#5e3714', '#2a160c', '#2a160c']}
locations={[0, 0.15, 0.3, 1]}
start={{ x: 0.5, y: 0 }}
end={{ x: 0.5, y: 1 }}
style={StyleSheet.absoluteFill}
/>
<Svg
width="358"
height="24"
viewBox="0 0 358 24"
style={{ position: 'absolute', left: 0, top: -23 }}>
<Path d="M70 24 C90 24 92 2 112 1 H246 C266 2 268 24 288 24 Z" fill="#a86c22" />
</Svg>
<View
style={{
position: 'absolute',
zIndex: 1,
left: '50%',
top: 24,
width: 150,
height: 18,
marginLeft: -75,
borderRadius: '50%',
backgroundColor: 'rgba(0,0,0,0.75)',
filter: 'blur(7px)',
}}
/>
<Pressable
accessibilityRole="button"
style={{
position: 'absolute',
zIndex: 2,
left: '50%',
top: -14,
transform: [{ translateX: '-50%' }],
width: 158,
height: 46,
padding: 0,
borderWidth: 0,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="158"
height="46"
viewBox="0 0 158 46"
style={{ position: 'absolute', left: 0, top: 0 }}>
<Defs>
<SvgLinearGradient id="liveFill" x1="0" y1="0" x2="1" y2="0">
<Stop offset="0" stopColor="#ff2f2f" />
<Stop offset="0.55" stopColor="#ff7a1f" />
<Stop offset="1" stopColor="#ffc21a" />
</SvgLinearGradient>
</Defs>
<Polygon
points="6.3,0 151.7,0 158,8.3 158,20.7 145.4,46 12.6,46 0,20.7 0,8.3"
fill="url(#liveFill)"
/>
</Svg>
<Text
style={{
flexShrink: 1,
fontFamily: 'Manrope_600SemiBold',
fontSize: 14,
color: '#ffffff',
}}>
Live Match
</Text>
</Pressable>
<View
style={{
borderRadius: 22,
paddingTop: 38,
paddingBottom: 12,
paddingHorizontal: 12,
gap: 14,
overflow: 'hidden',
}}>
<LinearGradient
colors={['#1c0e0a', '#1c0e0a', '#3e2110']}
locations={[0, 0.5, 1]}
start={{ x: 0.5, y: 0 }}
end={{ x: 0.5, y: 1 }}
style={StyleSheet.absoluteFill}
/>
<View
style={{
alignItems: 'center',
justifyContent: 'space-between',
flexDirection: 'row',
}}>
<View style={{ alignItems: 'center', gap: 10, flexShrink: 1, flexDirection: 'row' }}>
<View
style={{
width: 44,
height: 44,
borderRadius: 22,
backgroundColor: 'rgba(255,255,255,0.08)',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="26"
height="26"
viewBox="0 0 24 24"
accessibilityRole="image"
accessibilityLabel="Northport FC crest">
<Path d="M12 2l8 3v6c0 5-3.5 9-8 11-4.5-2-8-6-8-11V5z" fill="#1e3a8a" />
<Path d="M12 2v20c-4.5-2-8-6-8-11V5z" fill="#b91c1c" />
<SvgText
x="12"
y="15"
textAnchor="middle"
fontSize="7"
fill="#ffd34d"
fontFamily="Manrope_800ExtraBold">
NP
</SvgText>
</Svg>
</View>
<Text
style={{
flexShrink: 1,
fontFamily: 'Manrope_600SemiBold',
fontSize: 14,
color: '#ffffff',
}}>
Northport FC
</Text>
</View>
<View style={{ alignItems: 'center', gap: 10, flexShrink: 1, flexDirection: 'row' }}>
<Text
style={{
flexShrink: 1,
fontFamily: 'Manrope_600SemiBold',
fontSize: 14,
color: '#ffffff',
}}>
Vale City
</Text>
<View
style={{
width: 44,
height: 44,
borderRadius: 22,
backgroundColor: 'rgba(255,255,255,0.08)',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="26"
height="26"
viewBox="0 0 24 24"
accessibilityRole="image"
accessibilityLabel="Vale City crest">
<Circle cx="12" cy="12" r="10" fill="#f59e0b" />
<Circle cx="12" cy="12" r="7" fill="#111111" />
<SvgText
x="12"
y="14.5"
textAnchor="middle"
fontSize="7"
fill="#f59e0b"
fontFamily="Manrope_800ExtraBold">
VC
</SvgText>
</Svg>
</View>
</View>
</View>
<Text
style={{
marginTop: -4,
marginBottom: 2,
marginHorizontal: 0,
fontFamily: 'Manrope_700Bold',
fontSize: 46,
color: '#ffffff',
letterSpacing: 2,
textAlign: 'center',
}}>
4 : 1
</Text>
<View style={{ gap: 8, flexDirection: 'row' }}>
<Pressable
accessibilityRole="button"
style={{
flexGrow: 1,
flexShrink: 1,
flexBasis: 0,
height: 46,
borderRadius: 14,
borderWidth: 1,
borderColor: 'rgba(255,255,255,0.12)',
backgroundColor: 'rgba(255,255,255,0.06)',
alignItems: 'center',
justifyContent: 'center',
gap: 8,
flexDirection: 'row',
}}>
<Svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="#ffffff"
strokeWidth="1.8"
strokeLinecap="round"
strokeLinejoin="round">
<Rect x="3" y="5" width="18" height="16" rx="3" />
<Path d="M8 3v4M16 3v4M3 10h18" />
</Svg>
<Text
style={{
fontFamily: 'Manrope_600SemiBold',
fontSize: 13,
color: '#ffffff',
flexShrink: 1,
}}>
Northport
</Text>
</Pressable>
<Pressable
accessibilityRole="button"
style={{
flexGrow: 1,
flexShrink: 1,
flexBasis: 0,
height: 46,
borderRadius: 14,
borderWidth: 1,
borderColor: 'rgba(255,255,255,0.12)',
backgroundColor: 'rgba(255,255,255,0.06)',
alignItems: 'center',
justifyContent: 'center',
gap: 8,
flexDirection: 'row',
}}>
<Svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="#ffffff"
strokeWidth="1.8"
strokeLinecap="round"
strokeLinejoin="round">
<Path d="M21 12A9 9 0 1 1 12 3v9z" />
<Path d="M15 3.5A9 9 0 0 1 20.5 9H15z" />
</Svg>
<Text
style={{
fontFamily: 'Manrope_600SemiBold',
fontSize: 13,
color: '#ffffff',
flexShrink: 1,
}}>
Statistics
</Text>
</Pressable>
<Pressable
accessibilityRole="button"
accessibilityLabel="Save match"
style={{
width: 46,
height: 46,
borderRadius: 14,
borderWidth: 1,
borderColor: 'rgba(255,255,255,0.12)',
backgroundColor: 'rgba(255,255,255,0.06)',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="#ffffff"
strokeWidth="1.8"
strokeLinecap="round"
strokeLinejoin="round">
<Path d="M6 3h12v18l-6-4-6 4z" />
</Svg>
</Pressable>
</View>
<View style={{ flexDirection: 'row', gap: 8 }}>
<View
style={{
height: 44,
borderRadius: 12,
backgroundColor: '#3a1a12',
borderWidth: 1,
borderColor: 'rgba(255,120,60,0.25)',
alignItems: 'center',
justifyContent: 'center',
flex: 1,
flexDirection: 'row',
}}>
<Text
style={{
fontFamily: 'Manrope_600SemiBold',
fontSize: 14,
color: '#ffffff',
flexShrink: 1,
}}>
1.03
</Text>
</View>
<View
style={{
height: 44,
borderRadius: 12,
backgroundColor: '#3a1a12',
borderWidth: 1,
borderColor: 'rgba(255,120,60,0.25)',
alignItems: 'center',
justifyContent: 'center',
flex: 1,
flexDirection: 'row',
}}>
<Text
style={{
fontFamily: 'Manrope_600SemiBold',
fontSize: 14,
color: '#ffffff',
flexShrink: 1,
}}>
16.07
</Text>
</View>
<View
style={{
height: 44,
borderRadius: 12,
backgroundColor: '#3a1a12',
borderWidth: 1,
borderColor: 'rgba(255,120,60,0.25)',
alignItems: 'center',
justifyContent: 'center',
flex: 1,
flexDirection: 'row',
}}>
<Text
style={{
fontFamily: 'Manrope_600SemiBold',
fontSize: 14,
color: '#ffffff',
flexShrink: 1,
}}>
8.78
</Text>
</View>
</View>
</View>
</View>
<View style={{ marginTop: 30, borderRadius: 30, padding: 8, backgroundColor: '#2a1611' }}>
<Svg
width="358"
height="24"
viewBox="0 0 358 24"
style={{ position: 'absolute', left: 0, top: -23, zIndex: 1 }}>
<Path d="M70 24 C90 24 92 2 112 1 H246 C266 2 268 24 288 24 Z" fill="#2a1611" />
</Svg>
<View
style={{
position: 'absolute',
zIndex: 1,
left: '50%',
top: 24,
width: 150,
height: 18,
marginLeft: -75,
borderRadius: '50%',
backgroundColor: 'rgba(0,0,0,0.75)',
filter: 'blur(7px)',
}}
/>
<Pressable
accessibilityRole="button"
style={{
position: 'absolute',
zIndex: 2,
left: '50%',
top: -14,
transform: [{ translateX: '-50%' }],
width: 158,
height: 46,
padding: 0,
borderWidth: 0,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="158"
height="46"
viewBox="0 0 158 46"
style={{ position: 'absolute', left: 0, top: 0 }}>
<Defs>
<SvgLinearGradient id="liveFill" x1="0" y1="0" x2="1" y2="0">
<Stop offset="0" stopColor="#ff2f2f" />
<Stop offset="0.55" stopColor="#ff7a1f" />
<Stop offset="1" stopColor="#ffc21a" />
</SvgLinearGradient>
</Defs>
<Polygon
points="6.3,0 151.7,0 158,8.3 158,20.7 145.4,46 12.6,46 0,20.7 0,8.3"
fill="url(#liveFill)"
/>
</Svg>
<Text
style={{
flexShrink: 1,
fontFamily: 'Manrope_600SemiBold',
fontSize: 14,
color: '#ffffff',
}}>
Live Match
</Text>
</Pressable>
<Pressable
accessibilityRole="link"
onPress={() => router.navigate('/lineup')}
style={{
borderRadius: 22,
paddingTop: 38,
paddingBottom: 24,
paddingHorizontal: 12,
backgroundColor: '#190c09',
gap: 6,
}}>
<View
style={{
alignItems: 'center',
justifyContent: 'space-between',
flexDirection: 'row',
}}>
<View style={{ alignItems: 'center', gap: 10, flexShrink: 1, flexDirection: 'row' }}>
<View
style={{
width: 44,
height: 44,
borderRadius: 22,
backgroundColor: 'rgba(255,255,255,0.08)',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="26"
height="26"
viewBox="0 0 24 24"
accessibilityRole="image"
accessibilityLabel="Aurora United crest">
<Circle cx="12" cy="12" r="10" fill="#ffffff" />
<Path d="M5 15l7-10 7 10z" fill="#6d28d9" />
<Circle cx="12" cy="12" r="10" fill="none" stroke="#d4af37" strokeWidth="1.5" />
</Svg>
</View>
<Text
style={{
flexShrink: 1,
fontFamily: 'Manrope_600SemiBold',
fontSize: 14,
color: '#ffffff',
}}>
Aurora United
</Text>
</View>
<View style={{ alignItems: 'center', gap: 10, flexShrink: 1, flexDirection: 'row' }}>
<Text
style={{
flexShrink: 1,
fontFamily: 'Manrope_600SemiBold',
fontSize: 14,
color: '#ffffff',
}}>
Redcliffe
</Text>
<View
style={{
width: 44,
height: 44,
borderRadius: 22,
backgroundColor: '#ffffff',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
}}>
<Svg
width="26"
height="26"
viewBox="0 0 24 24"
accessibilityRole="image"
accessibilityLabel="Redcliffe crest">
<Circle cx="12" cy="12" r="10" fill="#dc2626" />
<Path d="M7 16l5-9 5 9z" fill="#ffffff" />
</Svg>
</View>
</View>
</View>
<Text
style={{
fontFamily: 'Manrope_700Bold',
fontSize: 46,
color: '#ffffff',
letterSpacing: 2,
textAlign: 'center',
}}>
3 : 0
</Text>
</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/components/stripes.tsx
import { useId } from 'react';
import { StyleSheet } from 'react-native';
import Svg, { Defs, Pattern, Rect } from 'react-native-svg';
type Props = {
first: string;
second: string;
/** Width of one band in px. */
size: number;
/** CSS gradient angle in degrees. */
angle: number;
};
export function Stripes({ first, second, size, angle }: Props) {
const id = useId();
return (
<Svg style={StyleSheet.absoluteFill} width="100%" height="100%">
<Defs>
<Pattern
id={id}
patternUnits="userSpaceOnUse"
width={size * 2}
height={size * 2}
patternTransform={`rotate(${angle - 90})`}>
<Rect width={size} height={size * 2} fill={first} />
<Rect x={size} width={size} height={size * 2} fill={second} />
</Pattern>
</Defs>
<Rect width="100%" height="100%" fill={`url(#${id})`} />
</Svg>
);
}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/live-football-scores-app-ui-design/assets';
export const asset = (name: string) => `${ASSET_BASE}/${name}`;src/lib/css.ts
import type { TextStyle, ViewStyle } from 'react-native';
// A few styles change with state, so they are kept as short CSS strings from the design.
const FACES: Record<number, string> = {400: 'Manrope_400Regular', 500: 'Manrope_500Medium', 600: 'Manrope_600SemiBold', 700: 'Manrope_700Bold', 800: 'Manrope_800ExtraBold'};
const px = (value: string) => (value.endsWith('%') ? (value as `${number}%`) : parseFloat(value));
function declarations(source: string) {
return source
.split(';')
.map((rule) => rule.split(':').map((part) => part.trim()))
.filter(([name, value]) => name && value);
}
export function css(source: string): ViewStyle {
const style: Record<string, unknown> = {};
for (const [name, ...rest] of declarations(source)) {
const value = rest.join(':');
if (name === 'background' || name === 'background-color') {
style.backgroundColor = value;
} else if (name === 'border') {
const [width, , ...color] = value.split(' ');
if (value === 'none' || value === '0') style.borderWidth = 0;
else {
style.borderWidth = parseFloat(width);
style.borderColor = color.join(' ');
}
} else if (name === 'display' && value === 'flex') {
style.flexDirection = style.flexDirection ?? 'row';
} else if (name === 'flex-direction') {
style.flexDirection = value;
} else if (name === 'align-items') {
style.alignItems = value;
} else if (name === 'justify-content') {
style.justifyContent = value;
} else if (name === 'box-shadow') {
style.boxShadow = value;
} else if (name === 'position') {
style.position = value === 'absolute' ? 'absolute' : 'relative';
} else if (name === 'opacity') {
style.opacity = parseFloat(value);
} else if (name === 'gap' || name === 'width' || name === 'height' || name === 'left' || name === 'top') {
style[name] = px(value);
} else if (name === 'border-radius') {
style.borderRadius = px(value);
} else if (name === 'padding') {
const [vertical, horizontal = vertical] = value.split(' ');
style.paddingVertical = px(vertical);
style.paddingHorizontal = px(horizontal);
} else if (name === 'white-space' && value === 'nowrap') {
style.flexShrink = 0;
} else if (name === 'flex-shrink') {
style.flexShrink = parseFloat(value);
} else if (name === 'flex') {
if (value === 'none') style.flexGrow = 0;
else style.flex = parseFloat(value);
}
}
return style as ViewStyle;
}
export function cssText(source: string): TextStyle {
const style: Record<string, unknown> = {};
for (const [name, value] of declarations(source)) {
if (name === 'color') style.color = value;
if (name === 'font-size') style.fontSize = parseFloat(value);
if (name === 'font-weight' && FACES[Number(value)]) style.fontFamily = FACES[Number(value)];
if (name === 'text-decoration' && value.startsWith('line-through')) {
style.textDecorationLine = 'line-through';
}
}
return style as TextStyle;
}About this design
The lineup screen is the standout. Players sit in formation on a green pitch and a curved tab selector wraps around the bottom, using SVG text on a path, so it is a good reference for custom sports navigation.
Dark ember backgrounds with a red to amber glow, angled match cards and a bright green pitch that breaks up the dark screens.
- Glowing onboarding with a slide action
- Angled live match cards with odds
- Starting eleven drawn on a full pitch
- Curved tab bar with text on an SVG path
Colour palette
Ember black
#120807
Smoke
#2A1712
Live red
#FF3B2F
Amber
#FFB020
Soft gold
#FFD27A
White
#FFFFFF
How to use this design
- 01
Pick what to copy
Copy the Live Football Scores 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
How is the curved tab bar made?
It is an SVG arc with text placed along the path using TextPath from react-native-svg, and a white dash marks the active tab.
Can I plug in a live scores API?
Yes. Scores, teams and players are plain values on each screen, so any football data provider can fill them.
Does it work for other sports?
The match cards work for any two team sport. Only the pitch needs redrawing for a court or field.
Is the Live Football Scores 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.



