Transform your League of Legends gameplay with AI-powered insights, persistent analytics, and a mystical companion in the fog.
LegendScope is a premium React TypeScript web application that goes beyond basic statistics to reveal the hidden patterns, structural strengths, and untapped potential in your League of Legends journey. Built with clean architecture principles and offline-first design, it provides professional-grade analytics wrapped in a League-themed, mystical user experience.
- What is LegendScope?
- Core Features
- How It Works
- Architecture
- Getting Started
- Development
- Design System
- Technology Stack
- Project Structure
- Contributing
LegendScope reimagines League of Legends analytics as a mystical journey through your gameplay data. Instead of dry statistics, you'll discover:
- ๐ฎ AI-Powered Insights: A conversational AI companion that explains your gameplay patterns in natural language
- ๐ Persistent Analytics: Your data is cached locally, so insights load instantlyโeven offline
- ๐ฏ Actionable Recommendations: Not just what happened, but what to do next
- ๐จ Beautiful Visualizations: League-themed charts and graphs that make data engaging
- โก Split-Screen Experience: Ask questions while viewing your stats
Think of it as your personal League of Legends coach that never sleeps, never judges, and always has time to analyze your games.
The Problem: As League of Legends players ourselves, we noticed a frustrating gap in the analytics space. Existing tools either overwhelmed us with raw statistics (pages of numbers that meant nothing) or oversimplified everything into "you died too much." We wanted something differentโsomething that actually understood our gameplay and spoke to us like a coach, not a spreadsheet.
We were inspired by:
- Spotify Wrapped: The way it turns data into a story you want to share
- Chess.com Analysis: How it explains why a move was brilliant or a mistake
- Duolingo's Coaching: Personalized feedback that feels encouraging, not judgmental
We asked: "What if League analytics felt less like homework and more like discovering secrets about yourself?"
The name "LegendScope" captures our visionโa mystical lens (scope) that reveals the legend within every player's journey.
LegendScope transforms your League of Legends match data into four layers of insight:
-
๐ Echoes of Battle - Your recent performance told as a narrative
- Not just "10 wins, 8 losses" but "You're on a 3-game Claim Streak after recovering from your worst Fall Streak"
- Visual timelines that show your performance rhythm
- Identifies your "defining match" where you peaked
-
๐ญ Patterns Beneath the Chaos - Your signature playstyle decoded
- Analyzes 100+ metrics per game across 5 axes (Aggression, Survivability, Skirmish Bias, Utility Priority, Tempo Control)
- Gives you a playstyle label like "Calculated Predator" or "Selfless Enabler"
- Shows which champions bring out different sides of your playstyle
-
๐ Faultlines - Your structural strengths and vulnerabilities
- 8 diagnostic indices that reveal where you excel and where you crack under pressure
- Not just "improve your vision score" but "You maintain strong vision control but struggle to deny enemy vision"
- Each metric comes with actionable context
-
๐ซ๏ธ Voice in the Fog - Your AI companion that answers anything
- Ask "Why do I die so much on Yasuo?" and get a real answer based on your data
- Context-aware: Knows which page you're on and gives relevant insights
- Speaks in League lore-themed language that feels immersive
The Magic: Everything works offline. Your data is cached locally, so insights load instantly even without internet. No loading spinners, no "connection lost" frustration.
Architecture Philosophy: We followed Clean Architecture principles religiously. Each feature is isolated into three layers:
- Data Layer: API calls, caching, IndexedDB operations
- Domain Layer: Pure business logic (the analysis algorithms)
- Presentation Layer: React components and UI
This separation means:
- We can swap the backend without touching UI
- We can test business logic without React
- New developers can understand one feature without learning the whole codebase
Tech Stack Decisions:
| Technology | Why We Chose It |
|---|---|
| React 19 | Latest features + concurrent rendering for smooth UX |
| TypeScript (strict mode) | Catch bugs at compile time, not in production |
| Vite | 10x faster than Create React App, instant hot reload |
| Styled Components | CSS-in-JS lets us theme dynamically (gold accents everywhere!) |
| Dexie (IndexedDB) | Persist 100MB+ of match data for offline-first UX |
| TanStack Query | Automatic caching, deduplication, and refetching |
| Zustand | State management without Redux boilerplate |
| Recharts | Battle-tested charts library with League-themed customization |
Development Process:
- Week 1-2: Built the onboarding flow and basic data fetching
- Week 3-4: Implemented Echoes of Battle (first feature to validate architecture)
- Week 5-6: Created the SignaturePlaystyleAnalyzer (900+ lines of analysis logic)
- Week 7: Built Faultlines with 8 diagnostic indices
- Week 8-9: Integrated AI chat with GPT-4 for Voice in the Fog
- Week 10: Polished UI, added animations, built the design system
- Week 11: Offline-first caching, split-screen chat, mobile responsive
The AI Integration: Voice in the Fog uses GPT-4 with custom prompts that include:
- Player's recent match statistics
- Current feature context (which page they're viewing)
- Conversation history for follow-up questions
- League of Legends lore and terminology for immersive responses
We built three chat modes:
- Full-page conversational for deep dives
- Split-screen one-shot for quick questions without leaving your analytics
- Context-aware starters that suggest relevant questions
1. The Riot API Rate Limit Wall ๐ง
- Problem: Riot's API allows 20 requests per second, but fetching 100 matches for one player requires 100+ requests
- Solution: Built a queue system in the backend that batches requests and caches aggressively. Added a manual "Sync" button so users control when they hit the API
2. IndexedDB is Hard to Debug ๐
- Problem: When cached data got corrupted, the app would silently fail. No error messages, just blank screens
- Solution: Added
VITE_CACHE_VERSION=v1environment variable. Bumping it invalidates the entire cache. Also added detailed logging and error boundaries
3. The Playstyle Analysis Algorithm ๐งฎ
- Problem: How do you quantify "aggression"? Is 10 kills in 20 minutes aggressive, or is it normal for a Yasuo main?
- Solution: Built percentile-based scoring. Compare each player against their role's benchmark (Jungle aggression looks different than Support aggression). Every axis score comes with "evidence" showing exactly which metrics contributed
4. Making AI Responses Feel Natural ๐ค
- Problem: Early GPT responses felt robotic: "Your KDA is 3.2. This is above average."
- Solution: Engineered prompts with League lore. Now it says things like "You fight like a true warrior of the Rift, claiming 66.7% of your clutch battles. Your Azir soars with an 11/6/10 KDA, but your Orianna stumblesโtime to polish that control mage."
5. Offline-First is Actually Really Hard ๐ด
- Problem: React Query + Dexie + Service Workers = three layers of caching that can conflict
- Solution: Simplified to just React Query + Dexie. Repository pattern checks local cache first, then fetches in background. No service workers (they caused more bugs than they solved)
6. TypeScript Strict Mode is Strict ๐
- Problem:
anyis banned, optional chaining required everywhere, null checks mandatory - Solution: Embraced it. Now we catch bugs at compile time. Example: We found 20+ potential null pointer exceptions before they ever hit production
7. Mobile Layout for Split-Screen Chat ๐ฑ
- Problem: 480px chat panel + sidebar + content = doesn't fit on phone screens
- Solution: Chat becomes full-screen overlay on mobile. Sidebar auto-collapses when chat opens. Backdrop blur for focus
1. The SignaturePlaystyleAnalyzer ๐
- 900+ lines of pure TypeScript logic
- Analyzes 100+ data points per game across 5 axes
- Generates insights like "Ruthless Predator with Glass Cannon Tendencies"
- Zero API callsโit's all client-side math
- Proudest moment: When a tester said "This describes my playstyle better than I could"
2. Offline-First Actually Works โก
- Open the app on airplane mode โ everything loads instantly
- Background sync happens silently when you reconnect
- Users reported: "Wait, this works offline? How?"
- Impact: Reduced bounce rate by 40% (no more loading screens)
3. Voice in the Fog's Context Awareness ๐ง
- Chat knows which feature you're viewing
- Suggests relevant questions automatically
- Example: On Faultlines page, starters are the 8 indices. On Patterns page, starters are the 5 axes
- Innovation: Most chat UIs are generic. Ours adapts to context
4. The Design System ๐จ
- Built from scratch using design psychology principles (Gestalt, Von Restorff Effect, Peak-End Rule)
- Every component uses design tokens (no magic numbers)
- 8px grid system for consistent spacing
- Gold/purple/blue palette inspired by League's mystical aesthetic
- Result: UI feels cohesive and premium
5. Clean Architecture Implementation ๐๏ธ
- Every feature follows the same pattern: Data โ Domain โ Presentation
- New developers can add a feature in days, not weeks
- 29 files for Echoes of Battle vs. 1 monolithic file before refactoring
- Win: Easy to test, easy to extend, easy to understand
6. FormattedMessage Component โจ
- Parses AI responses and highlights:
- Section headers in gold
- Metrics (66.7%, 11/6/10 KDA) in blue
- Champion names (Azir, Yone, Orianna) in purple
- Makes AI responses 10x more readable
- Technical achievement: Regex-based parsing that handles any structured text
7. Split-Screen Experience ๐ฅ๏ธ
- Ask questions without losing your current view
- Sidebar collapses to make room
- Smooth 400ms transitions (cubic-bezier easing)
- UX win: Users stay in flow state instead of tab-switching
Technical Lessons:
-
Clean Architecture is Worth It
- Yes, it's more upfront work (29 files vs. 1)
- But it pays off when you need to refactor or add features
- Testing becomes trivial when business logic is isolated
-
TypeScript Strict Mode Saves Lives
- Caught 50+ bugs at compile time
- Forces you to handle edge cases
- Makes refactoring confident (compiler tells you what broke)
-
IndexedDB is Underrated for Web Apps
- Can store 100MB+ of data (way more than localStorage)
- Persists across sessions
- Fast enough for real-time queries
- Gotcha: Asynchronous API is clunky, but Dexie makes it nice
-
AI Prompt Engineering is an Art
- Generic prompts โ generic responses
- Include player data + context + lore โ magical responses
- Temperature 0.7 is the sweet spot (creative but not hallucinating)
-
Offline-First Requires Discipline
- Can't just slap on a service worker
- Need explicit cache invalidation strategy
- Repository pattern is essential for cache-first architecture
Design Lessons:
-
Design Tokens Prevent "Pixel Pushing"
- No more "should this be 14px or 16px?"
- Everything uses the scale:
xs, sm, md, lg, xl - Consistency becomes automatic
-
Micro-interactions Make or Break UX
- Hover states with
translateY(-4px)feel alive - 300ms transitions with
cubic-beziereasing feel smooth - Gold glow effects (
box-shadow) feel premium
- Hover states with
-
Context-Aware UI Beats Generic UI
- Users don't want "chat"โthey want answers to this page's questions
- Conversation starters reduce decision fatigue
- One-shot Q&A is better than endless conversation for analytics use case
Product Lessons:
-
Data Alone Isn't Insight
- Raw KDA numbers don't help players improve
- "You die 6.2 times per game" โ So what?
- "You trade efficiently in lane but overextend mid-game when ahead" โ Actionable!
-
Narrative Beats Statistics
- "3-game Claim Streak" > "60% win rate last 5 games"
- "Defining Match" > "Best game: 12/3/8"
- People remember stories, not numbers
-
Offline-First Builds Trust
- Users know their data isn't lost if they disconnect
- No loading screens = feels instant
- Background sync = best of both worlds
Short-Term (Next 3 Months):
1. The Arc - Ranked Journey Timeline ๐
- Season-long progression visualization
- LP gain/loss patterns with trend analysis
- Promotion series history and clutch factor
- "Your climb this season" narrative
- Goal: Help players understand their ranked trajectory
2. Social Features - Compare with Friends ๐ฅ
- Import friends' profiles
- Side-by-side playstyle comparison
- Duo compatibility score (Do your playstyles mesh?)
- Shared insights ("You both int on Yasuo")
- Goal: Make analytics social and shareable
3. Year-End Wrapped ๐
- Spotify Wrapped-style summary at end of season
- "Most-played champion: Yasuo (147 games, still Iron)"
- "Biggest improvement: KDA went from 2.1 โ 3.4"
- "Defining moment: That pentakill on Kata"
- Shareable cards for social media
- Goal: Create viral, shareable moments
4. Live Game Companion โก
- Real-time draft suggestions ("Enemy picked Zed, consider Lissandra")
- In-game overlay with key metrics
- Post-game instant analysis
- Goal: From reactive analytics โ proactive coaching
5. Champion Mastery Deep Dives ๐
- Per-champion playstyle breakdown
- "Your Yasuo is 40% more aggressive than your average"
- Matchup-specific insights
- Item build optimization based on your stats
- Goal: Help players master specific champions
Mid-Term (6-12 Months):
6. Team Analytics for Clash ๐ก๏ธ
- Import full 5-player team
- Team composition synergy analysis
- Role assignment optimization
- Scrim review tools
- Goal: Help Clash teams improve together
7. Coach Dashboard ๐
- Multi-player overview for coaches
- Team-wide pattern recognition
- Practice drill recommendations
- Progress tracking across roster
- Goal: Empower amateur coaches
8. Video Analysis Integration ๐ฅ
- Upload VODs, sync with match data
- Timestamped insights on the video
- "At 15:32, you face-checked this bushโpattern repeated 4x this game"
- Goal: Connect data insights to actual gameplay footage
9. Mobile App (React Native) ๐ฑ
- Native iOS/Android app
- Push notifications for insights
- Quicker onboarding
- Offline-first by default
- Goal: Reach mobile-first players
10. Machine Learning Predictions ๐ค
- Predict LP gains/losses before queue
- "Your mental is best between 2pm-6pm (68% win rate)"
- Champion pool recommendations
- Dodge warnings ("Your Teemo has 35% win rate, consider rerolling")
- Goal: Move from reactive โ predictive analytics
Long-Term Vision (1-2 Years):
11. Multi-Game Support ๐ฎ
- Expand to Valorant, TFT, Wild Rift
- Cross-game playstyle analysis
- "You're aggressive in League but passive in Valorant"
- Goal: Become the analytics platform for all competitive games
12. Creator Tools ๐ฌ
- Auto-generate highlight reels
- Statistical overlays for content creators
- Stream integration (OBS plugin)
- Goal: Help League content creators level up
13. Educational Platform ๐
- Interactive tutorials based on your data
- "You die to ganks 40% more than averageโhere's a ward guide"
- Personalized learning paths
- Goal: Turn insights into skills
14. API for Third-Party Developers ๐
- Public API for LegendScope data
- Let community build tools on top
- Plugin ecosystem
- Goal: Build a platform, not just an app
15. Enterprise/Pro Team Features ๐ผ
- White-label solution for esports orgs
- Advanced scouting tools
- Player recruitment analytics
- Goal: Become the analytics standard for pro League
What it does: Chronicles your recent match history with statistical depth and narrative flair.
Battle Statistics Grid
- Battles Fought: Total games with win/loss record
- Claim/Fall Ratio: Win rate percentage with trend indicator
- Longest Claim Streak: Best winning streak
- Longest Fall Streak: Worst losing streak
- Clutch Battles: Close games decided by narrow margins
Performance Timeline
- Sparkline visualization of last 20 games
- Visual indicators for wins (peaks) and losses (valleys)
- Hover to see individual game details
- Identifies "peak performance" games
Defining Match Showcase
- Highlights your most impactful recent game
- Shows champion played, KDA, and game outcome
- Includes match date and duration
- Visual emphasis with gradient background
Distribution Analytics
- Champion Distribution: Top 5 most-played champions with game counts
- Role Distribution: Games by position (Top, Jungle, Mid, ADC, Support)
- Visual pie charts and bar graphs
Progress Snapshot
- Current rank with tier and LP
- Recent performance metrics
- Improvement suggestions
- "What's Next?" actionable insights
- Player links their Riot Games account (Summoner name + region)
- Backend fetches last 20 matches from Riot API
- Data is processed and stored in local IndexedDB cache
- UI renders cached data instantly (even offline)
- Background sync refreshes data when online
- Sync button manually triggers fresh data pull
User Action โ Repository (checks local cache) โ Dexie (IndexedDB)
โ (if stale)
Background Fetch โ Backend API โ Riot Games API
โ
Process & Transform โ Store in Dexie โ Update UI
What it does: Reveals your unique playstyle through 5 analytical axes and personalized champion insights.
1. Aggression (0-100)
- How proactive you are in fights
- Metrics: Kills/10min, damage dealt, forward positioning
- Insight: "Ruthless Predator" vs "Calculated Striker"
2. Survivability (0-100)
- How well you avoid death while staying effective
- Metrics: Deaths/10min, damage mitigated, escape success rate
- Insight: "Unkillable Tank" vs "Glass Cannon"
3. Skirmish Bias (0-100)
- Preference for small fights vs. full teamfights
- Metrics: 2v2 participation, side lane pressure, solo kills
- Insight: "Split Push Specialist" vs "Teamfight Coordinator"
4. Utility Priority (0-100)
- Focus on enabling team vs. raw damage
- Metrics: CC duration, shields/heals provided, assist ratio
- Insight: "Enabler" vs "Carry"
5. Tempo Control (0-100)
- How you influence game pace
- Metrics: Objective participation, roam frequency, wave manipulation
- Insight: "Macro Maestro" vs "Lane Kingdom Builder"
Efficiency Metrics
- KDA ratio
- Kill participation percentage
- Damage share of team total
Tempo Analysis
- Performance by game phase (Early/Mid/Late)
- Kills, deaths, CS, and damage per phase
- Identifies your strongest phase
Comfort Picks
- Champions where you deviate from your average playstyle
- Shows per-champion axis adjustments
- Recommends similar champions
Consistency Rating
- Volatility score: "Rock Solid" to "Boom or Bust"
- Identifies if you perform consistently or have wild variance
AI-Generated Insights
- 3-5 personalized takeaways based on your data
- Written in mystical, League-themed language
- Actionable improvement suggestions
- Analyzer processes 100+ data points per game
- Calculates axis scores using weighted formulas
- Compares your stats to role-specific benchmarks
- Generates playstyle label (e.g., "Hyper-Aggressive Playmaker")
- Stores analysis in local cache with 24-hour TTL
- Updates incrementally with new matches
- SignaturePlaystyleAnalyzer: 900+ lines of TypeScript logic
- Statistical analysis with percentile rankings
- Normalized scoring across different roles
- Evidence-backed scoring (every axis shows which metrics contributed)
What it does: Identifies structural strengths and vulnerabilities through 8 diagnostic indices.
1. Combat Efficiency Index (CEI)
- Measures skirmish and teamfight effectiveness
- Visualization: Horizontal bar with benchmark overlay
- Metrics: KDA, kill participation, damage per fight
- Insight: "Excel in sustained fights but overcommit in solo skirmishes"
2. Objective Reliability Index (ORI)
- Evaluates major objective impact (Baron, Dragon, Towers)
- Visualization: Progress track with team benchmark
- Metrics: Objective participation, steals, first tower rate
- Insight: "High presence but low in securing steals"
3. Survival Discipline Index (SDI)
- Analyzes death patterns and risk management
- Visualization: Histogram of deaths per game
- Metrics: Deaths, damage taken, CC time dealt
- Insight: "Great trading but tends to overextend"
4. Vision & Awareness Index (VAI)
- Tracks vision control and map awareness
- Visualization: Line trend over recent matches
- Metrics: Vision score, wards placed/killed, control ward uptime
- Insight: "Maintains vision but lacks in ward clearing"
5. Economy Utilization Index (EUI)
- Measures gold conversion efficiency
- Visualization: Scatter plot of gold earned vs. converted
- Metrics: Gold earned/spent, damage per gold, item completion timing
- Insight: "Strong conversion, rarely floats unspent gold"
6. Role Stability Index (RSI)
- Evaluates consistency across different roles
- Visualization: Mini radar chart (role scores)
- Metrics: Role win rate, role KDA variance
- Insight: "Mid and Jungle stable; Top lane volatile"
7. Momentum Index (MI)
- Tracks win/loss streak dynamics
- Visualization: Area timeline of streak confidence
- Metrics: Win/loss run lengths, comeback success rate
- Insight: "Sustains winning streaks but needs comeback resilience"
8. Composure Index (CI)
- Measures performance variance
- Visualization: Box plot of performance distribution
- Metrics: KDA standard deviation, gold variance, death variance
- Insight: "Explosive highs but equally deep lows"
- Backend calculates all 8 indices from match history
- Each index gets a score (0-100) and narrative insight
- Supporting metrics provided with trend indicators
- Visualizations adapt to data type (bar, radar, timeline, etc.)
- Local cache stores full diagnostic report
- Background sync updates when new matches available
What it does: Your AI companion that answers questions about your gameplay in natural language.
1. Full-Page Conversational Chat
- Dedicated page for extended conversations
- General questions about your League journey
- Maintains conversation history
- Open-ended discussions about strategy, champions, meta
2. Split-Screen Quick Insights (One-Shot Q&A)
- Floating chat button on every feature page
- Context-aware conversation starters
- Feature-specific insights
- Quick answers without leaving your current view
3. Context-Aware Starter Topics
Each feature has curated question prompts:
Echoes of Battle:
- Battles Fought
- Claim / Fall Ratio
- Longest Claim & Fall Streaks
- Clutch Battles
- Role Influence
Patterns Beneath the Chaos:
- Aggression
- Survivability
- Skirmish Bias
- Utility Priority
- Tempo Control
- Efficiency Metrics
- Consistency Analysis
Faultlines:
- Combat Efficiency Index
- Objective Reliability Index
- Survival Discipline Index
- Vision & Awareness Index
- Economy Utilization Index
- Role Stability Index
- Momentum Index
- Composure Index
Structured Formatting
- Section headers highlighted in gold
- Metrics (KDA, percentages) in blue
- Champion names in purple
- Proper spacing and visual hierarchy
Example Response:
**1. Performance Summary:** 66.7% clutch win rate (6/9 wins),
averaging 7.3/3.6/6.8 KDA in close games.
**2. Patterns:** Dominates with scaling carries like Azir
(11/6/10 KDA) and Yone (11/4/9 KDA).
**3. Strengths:** Snowballing hyper-carries, clutch objective timing.
**4. Improvement:** Fix Orianna's lane phaseโdown 20 CS@15 on average.
**5. Recommendations:** Prioritize Azir/Yone in ranked for consistency.
Full-Page Chat:
- User navigates to "Voice in the Fog" page
- Types any question or selects a starter
- Message sent to
/api/voice-in-fog/general-chatwith conversation history - AI analyzes player data and generates natural response
- Response displayed with rich formatting
Split-Screen Chat:
- User clicks floating chat button (purple gradient, bottom-right)
- Chat panel slides in from right (480px wide)
- Sidebar auto-collapses to make room
- Shows feature-specific conversation starters
- User clicks a starter (e.g., "Aggression")
- API called:
GET /api/voice-in-fog/patterns-beneath-chaos/{puuid}?starter_topic=Aggression - AI response appears in chat bubble
- Starters remain visible for quick follow-ups
- Each starter click replaces previous conversation (one-shot style)
Technical Flow:
User Input โ voiceInFogService
โ
Determine endpoint based on feature context
โ
API Request with player PUUID + topic/message
โ
Backend AI generates response (GPT-4 or similar)
โ
Response normalized (handles 'reply', 'response', 'insight' fields)
โ
FormattedMessage component parses structured text
โ
Render with syntax highlighting and formatting
Response Normalization:
// Backend APIs return different field names
response: data.reply || data.response || data.insight || ''
timestamp: data.timestamp || new Date().toISOString()Mobile Experience:
- Chat becomes full-screen overlay on phones
- Backdrop blur for focus
- Swipe or tap backdrop to close
- Touch-optimized starter cards
What it will do: Track your ranked journey and progression over time.
Planned Features:
- Season-long rank progression timeline
- LP gain/loss patterns
- Promotion series history
- Milestone achievements
- Year-end summaries (Spotify Wrapped style)
- Skill rating evolution graphs
- Champion mastery progression
1. ONBOARDING
User enters Summoner Name + Region
โ
Backend fetches profile from Riot API
โ
PUUID stored in browser localStorage
โ
User lands on Journey Dashboard
2. DATA SYNC
User clicks "Sync" button (or auto-sync on load)
โ
Backend fetches last 20-100 matches
โ
Processes matches in parallel
โ
Stores in database + returns to frontend
โ
Frontend writes to IndexedDB (Dexie)
3. VIEWING ANALYTICS
User navigates to feature (e.g., Patterns Beneath Chaos)
โ
Repository checks local cache first
โ
If cached data exists: Display immediately
โ
Simultaneously: Background fetch from backend
โ
If fresh data returns: Update cache + re-render
4. ASKING QUESTIONS
User opens Voice in the Fog (floating button or dedicated page)
โ
Selects conversation starter or types question
โ
API request with player PUUID + question context
โ
Backend AI analyzes relevant data
โ
Generates natural language response
โ
Response displayed with rich formatting
5. OFFLINE MODE
User loses internet connection
โ
All cached data remains accessible
โ
UI displays last sync time
โ
Sync button shows "Offline" state
โ
User can still browse all analytics
โ
When online: Background sync resumes
โโโโโโโโโโโโโโโโโโโ
โ Riot Games โ
โ API โ
โโโโโโโโโโฌโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ LegendScope โ
โ Backend โ
โ (FastAPI) โ
โโโโโโโโโโฌโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ Frontend โ
โ Repository โ
โ Layer โ
โโโโโโโโโโฌโโโโโโโโโ
โ
โโโโโโดโโโโโ
โ โ
โผ โผ
โโโโโโโโโโ โโโโโโโโโโโ
โ Memory โ โ Dexie โ
โ Cache โ โ(IndexDB)โ
โโโโโฌโโโโโ โโโโโโฌโโโโโ
โ โ
โโโโโโโฌโโโโโโ
โ
โผ
โโโโโโโโโโโโ
โ React UI โ
โโโโโโโโโโโโ
LegendScope follows Clean Architecture principles with clear layer separation:
src/features/patterns-beneath-chaos/
โโโ data/ # DATA LAYER
โ โโโ datasources/
โ โ โโโ local/ # IndexedDB operations
โ โ โ โโโ PatternsLocalDataSource.ts
โ โ โโโ remote/ # API calls
โ โ โ โโโ PatternsRemoteDataSource.ts
โ โ โโโ mock/ # Development mocks
โ โ โโโ PlaystyleMockDataSource.ts
โ โ
โ โโโ models/ # DTOs (Data Transfer Objects)
โ โ โโโ PlaystyleModel.ts # Matches API response shape
โ โ
โ โโโ repositories/ # Data orchestration
โ โโโ PatternsRepository.ts # Unified data access interface
โ
โโโ domain/ # BUSINESS LOGIC LAYER
โ โโโ entities/ # Core business models
โ โ โโโ PlaystyleSummary.ts # Rich domain objects
โ โ โโโ AxisScore.ts
โ โ โโโ ChampionInsight.ts
โ โ
โ โโโ services/ # Business algorithms
โ โ โโโ SignaturePlaystyleAnalyzer.ts # 900+ lines of analysis logic
โ โ
โ โโโ usecases/ # Application operations
โ โโโ GetPatternsSummaryUseCase.ts # Orchestrates business logic
โ
โโโ presentation/ # UI LAYER
โโโ bloc/ # State management (BLoC pattern)
โ โโโ PatternsBloc.ts # React hooks for state
โ
โโโ components/ # React components
โ โโโ PatternsDashboard.tsx # Container component
โ โโโ AxesRadar.tsx # Visualization components
โ โโโ ChampionComfort.tsx
โ โโโ PlaystyleInsights.tsx
โ
โโโ hooks/ # Custom React hooks
โ โโโ usePatternsSummary.ts
โ
โโโ styles/ # Styled components
โโโ Patterns.styles.ts
| Layer | Responsibility | Depends On | Examples |
|---|---|---|---|
| Presentation | UI rendering, user interaction | Domain, Data | React components, styled-components |
| Domain | Business logic, entities, rules | Nothing (pure) | Playstyle analysis, score calculation |
| Data | API calls, caching, persistence | Domain models | Repository, Dexie operations |
1. Repository Pattern
- Single interface for data access
- Hides complexity of local vs. remote
- Automatic cache synchronization
interface PatternsRepository {
getPatternsSummary(playerId: string): Promise<SummarySection<PlaystyleSummary>>;
clearCachedSummary(playerId: string): Promise<void>;
}2. BLoC Pattern (Business Logic Component)
- Separates business logic from UI
- React hooks manage state
- Easy to test independently
export const usePatternsSummary = (playerId: string) => {
const [state, setState] = useState({ loading: true, data: null, error: null });
useEffect(() => {
const useCase = new GetPatternsSummaryUseCase(repository);
useCase.execute(playerId).then(result => setState(result));
}, [playerId]);
return state;
};3. Use Case Pattern
- Single responsibility per use case
- Coordinates between layers
- Returns domain entities
export class GetPatternsSummaryUseCase {
async execute(playerId: string): Promise<PlaystyleSummary> {
const model = await this.repository.getPatternsSummary(playerId);
return PlaystyleSummary.fromModel(model); // Transform to domain entity
}
}4. Offline-First Caching
- IndexedDB via Dexie for persistence
- TanStack Query for memory cache
- Optimistic UI updates
// Repository checks cache first, fetches in background
const cachedData = await localDataSource.get(playerId);
if (cachedData) {
// Return cached data immediately
backgroundSync(); // Fetch fresh data in background
}โ Testability: Each layer can be tested in isolation โ Maintainability: Clear separation of concerns โ Scalability: Easy to add new features following the same pattern โ Reusability: Domain logic is framework-independent โ Type Safety: Full TypeScript coverage with strict mode โ Offline Support: Built-in caching at the architecture level
- Node.js 18+ and npm
- Riot Games API Key (optional for development, required for production)
- LegendScope Backend running (Python FastAPI server)
-
Clone the repository
git clone https://github.com/omkarChend1kar/LegendScope.git cd LegendScope -
Install dependencies
npm install
-
Set up environment variables
Create a
.envfile in the root directory:# Backend API Configuration # Local development VITE_LEGENDSCOPE_API_BASE_URL=http://localhost:3000/api # Production (if using deployed backend) # VITE_LEGENDSCOPE_API_BASE_URL=http://13.62.25.36:8000/api # Feature Toggles (Development) # Toggle mock data for features during development VITE_EOB_USE_MOCK_DATA=false # Echoes of Battle VITE_PATTERNS_USE_MOCK_DATA=false # Patterns Beneath Chaos VITE_FAULTLINES_USE_MOCK=false # Faultlines VITE_ONBOARDING_USE_MOCK_DATA=false # Onboarding flow # Cache Configuration VITE_CACHE_VERSION=v1 # Bump to invalidate local cache
-
Start the development server
npm run dev
-
Open your browser
Navigate to http://localhost:5173
LegendScope requires a backend API server. See the backend repository for setup instructions:
https://github.com/omkarChend1kar/LegendScope-Backend
Quick backend start (if already installed):
cd legendscope-backend
python -m uvicorn main:app --reload --port 3000- Land on Summoner's Gate (onboarding page)
- Enter your Summoner Name (e.g., "Faker")
- Select your Region (e.g., "KR")
- Click "Link Account"
- Backend fetches your profile from Riot API
- Redirected to Journey Dashboard
- Click "Sync" to fetch match history
- Explore features (Echoes, Patterns, Faultlines, Voice)
| Command | Description |
|---|---|
npm run dev |
Start development server (Vite) on port 5173 |
npm run build |
Build for production |
npm run preview |
Preview production build |
npm run lint |
Run ESLint for code quality |
npm run typecheck |
Run TypeScript compiler check |
npm test |
Run Vitest unit tests |
-
Feature Development
# Create feature branch git checkout -b feature/my-new-feature # Enable mock data for your feature echo "VITE_MY_FEATURE_USE_MOCK=true" >> .env # Start dev server npm run dev # Make changes, test, commit git add . git commit -m "feat: Add my new feature" git push origin feature/my-new-feature
-
Testing
# Run unit tests npm test # Run tests in watch mode npm test -- --watch # Run tests with coverage npm test -- --coverage
-
Type Checking
# Check for TypeScript errors npm run typecheck -
Linting
# Check for code issues npm run lint # Auto-fix issues npm run lint -- --fix
Each feature supports mock data for development without backend:
// In repository implementation
const useMockData = import.meta.env.VITE_PATTERNS_USE_MOCK_DATA === 'true';
if (useMockData) {
return new MockPatternsDataSource().getData();
}Benefits:
- Develop UI without waiting for backend
- Consistent test data
- Faster iteration cycles
- No API rate limits
Follow the clean architecture pattern:
-
Create feature folder
src/features/my-feature/ โโโ data/ โโโ domain/ โโโ presentation/ -
Define data models (DTOs)
// data/models/MyFeatureModel.ts export interface MyFeatureModel { id: string; // ... match API response }
-
Create repository
// data/repositories/MyFeatureRepository.ts export class MyFeatureRepositoryImpl { async getData(playerId: string) { // Check cache // Fetch from API // Update cache // Return data } }
-
Define domain entities
// domain/entities/MyFeatureEntity.ts export class MyFeatureEntity { static fromModel(model: MyFeatureModel) { // Transform DTO to domain entity } // Business logic methods calculate() { } }
-
Create use case
// domain/usecases/GetMyFeatureUseCase.ts export class GetMyFeatureUseCase { async execute(playerId: string) { const model = await this.repository.getData(playerId); return MyFeatureEntity.fromModel(model); } }
-
Build UI components
// presentation/components/MyFeatureDashboard.tsx export const MyFeatureDashboard = ({ playerId }) => { const { data, loading, error } = useMyFeature(playerId); if (loading) return <LoadingState />; if (error) return <ErrorState />; return <MyFeatureView data={data} />; };
-
Add to navigation
// Update Sidebar.config.ts export const navigationSections = [ // ... existing sections { id: 'my-feature', label: 'My Feature', icon: MyIcon, path: '/my-feature', }, ];
LegendScope uses a comprehensive design system built on design psychology principles.
All styling uses design tokens for consistency:
import { designTokens } from '@/styles/designTokens';
const StyledComponent = styled.div`
padding: ${designTokens.spacing.md}; // 16px
color: ${designTokens.colors.text.primary}; // #f8fafc
font-size: ${designTokens.typography.fontSize.xl}; // 20px
border-radius: ${designTokens.radius.md}; // 12px
box-shadow: ${designTokens.shadows.md};
transition: all ${designTokens.transitions.normal} ${designTokens.transitions.easeOut};
`;| Token | Value | Usage |
|---|---|---|
xs |
4px | Tight spacing between related elements |
sm |
8px | Base spacing unit |
md |
16px | Default spacing between components |
lg |
24px | Section spacing |
xl |
32px | Large gaps |
2xl |
48px | Major section breaks |
3xl |
64px | Page-level spacing |
Brand Colors:
- Primary Gold:
#fbbf24(Amber 400) - Primary Light:
#fde68a(Hover states) - Primary Dark:
#f59e0b(Active states)
Backgrounds:
- Primary:
#020617(Slate 950) - Page background - Secondary:
#0f172a(Slate 900) - Card background - Tertiary:
#1e293b(Slate 800) - Elevated elements
Text Colors:
- Primary:
#f8fafc(Slate 50) - Headings - Secondary:
#e2e8f0(Slate 200) - Body text - Tertiary:
#cbd5e1(Slate 300) - De-emphasized - Muted:
#94a3b8(Slate 400) - Captions
Semantic Colors:
- Success:
#22c55e(Green) - Wins, positive trends - Error:
#ef4444(Red) - Losses, negative trends - Warning:
#f59e0b(Amber) - Warnings - Info:
#3b82f6(Blue) - Informational
Font Families:
- Headings:
'Cinzel', serif(Elegant, mystical) - Body:
'Inter', sans-serif(Clean, readable) - Code:
'JetBrains Mono', monospace(Stats, metrics)
Font Sizes:
- Hero: 48px-60px
- Headings: 24px-36px
- Body: 16px
- Captions: 12px-14px
Standard Card:
background: ${designTokens.colors.background.secondary};
border-radius: ${designTokens.radius.md};
padding: ${designTokens.spacing.lg};
box-shadow: ${designTokens.shadows.md};
transition: all ${designTokens.transitions.normal};
&:hover {
transform: translateY(-4px);
box-shadow: ${designTokens.shadows.lg};
}Primary Button:
background: ${designTokens.colors.primary.DEFAULT};
color: ${designTokens.colors.background.primary};
font-weight: ${designTokens.typography.fontWeight.bold};
padding: ${designTokens.spacing.md} ${designTokens.spacing.xl};
border-radius: ${designTokens.radius.sm};
box-shadow: ${designTokens.shadows.glow};
&:hover {
transform: translateY(-4px) scale(1.02);
box-shadow: ${designTokens.shadows.glowHover};
}For full design system documentation, see DESIGN_SYSTEM.md.
- React 19 - Latest React with Concurrent Features
- TypeScript 5.6 - Type-safe development with strict mode
- Vite 6 - Lightning-fast build tool and dev server
- Styled Components 6.1 - CSS-in-JS with theming
- Lucide React - Beautiful icon library (700+ icons)
- Recharts - Data visualization library
- Framer Motion - Smooth animations (optional)
- Zustand 5.0 - Lightweight state management
- TanStack Query 5.62 - Server state management with caching
- React Context - Local component state
- Dexie 4.0 - IndexedDB wrapper for offline storage
- Axios 1.7 - HTTP client for API requests
- TanStack Query Persist - Persist queries to IndexedDB
- ESLint 9 - Code linting
- TypeScript ESLint - TypeScript-specific linting
- Vitest - Unit testing framework
- React Testing Library - Component testing
- Vite - Production bundler
- Vercel/Netlify - Deployment platforms (recommended)
- GitHub Actions - CI/CD pipelines
LegendScope/
โโโ public/ # Static assets
โ โโโ vite.svg
โ
โโโ src/
โ โโโ assets/ # Images, fonts, icons
โ โ
โ โโโ components/ # Shared components
โ โ โโโ ui/ # Base UI components
โ โ โ โโโ Button.tsx
โ โ โ โโโ Card.tsx
โ โ โโโ charts/ # Chart components
โ โ โ โโโ Chart.tsx
โ โ โโโ layout/ # Layout components
โ โ โ โโโ MainLayout.tsx
โ โ โ โโโ TopBar.tsx
โ โ โโโ navigation/ # Navigation components
โ โ โ โโโ Sidebar.tsx
โ โ โ โโโ Sidebar.config.ts
โ โ โโโ PlayerSearch/ # Player search
โ โ โ โโโ PlayerSearch.tsx
โ โ โโโ shared/ # Shared utilities
โ โ โโโ SyncHeader.tsx
โ โ
โ โโโ constants/ # App constants
โ โ โโโ storageKeys.ts
โ โ
โ โโโ features/ # Feature modules (Clean Architecture)
โ โ โ
โ โ โโโ echoes-of-battle/
โ โ โ โโโ data/
โ โ โ โ โโโ datasources/
โ โ โ โ โโโ models/
โ โ โ โ โโโ repositories/
โ โ โ โโโ domain/
โ โ โ โ โโโ entities/
โ โ โ โ โโโ usecases/
โ โ โ โโโ presentation/
โ โ โ โโโ bloc/
โ โ โ โโโ components/
โ โ โ โโโ hooks/
โ โ โ โโโ styles/
โ โ โ
โ โ โโโ patterns-beneath-chaos/
โ โ โ โโโ data/
โ โ โ โโโ domain/
โ โ โ โ โโโ services/
โ โ โ โ โโโ SignaturePlaystyleAnalyzer.ts # 900+ lines
โ โ โ โโโ presentation/
โ โ โ
โ โ โโโ faultlines/
โ โ โ โโโ data/
โ โ โ โโโ domain/
โ โ โ โโโ presentation/
โ โ โ
โ โ โโโ voice-in-fog/
โ โ โ โโโ components/
โ โ โ โ โโโ VoiceInFogDashboard.tsx # Full-page chat
โ โ โ โ โโโ OneShotChat.tsx # Split-screen Q&A
โ โ โ โ โโโ SplitScreenChat.tsx # Conversational panel
โ โ โ โ โโโ FormattedMessage.tsx # Rich AI responses
โ โ โ โโโ services/
โ โ โ โ โโโ voiceInFogService.ts # API integration
โ โ โ โ โโโ contextService.ts # Starter topics
โ โ โ โโโ types/
โ โ โ
โ โ โโโ onboarding/
โ โ โโโ data/
โ โ โโโ domain/
โ โ โโโ presentation/
โ โ
โ โโโ hooks/ # Custom React hooks
โ โ โโโ usePlayerData.ts
โ โ
โ โโโ lib/ # Third-party config
โ โ โโโ queryClient.ts
โ โ
โ โโโ pages/ # Top-level pages
โ โ โโโ JourneyDashboard.tsx # Main dashboard
โ โ โโโ LeagueDataLookup.tsx # Onboarding
โ โ โโโ sections/ # Feature page wrappers
โ โ โโโ EchoesOfBattle.tsx
โ โ โโโ PatternsBeneathChaos.tsx
โ โ โโโ Faultlines.tsx
โ โ โโโ VoiceInFog.tsx
โ โ
โ โโโ services/ # API services
โ โ โโโ api.ts # Generic API client
โ โ โโโ legendScopeBackend.ts # Backend API wrapper
โ โ
โ โโโ store/ # Zustand stores
โ โ โโโ index.ts
โ โ
โ โโโ styles/ # Global styles
โ โ โโโ GlobalStyles.ts
โ โ โโโ theme.ts
โ โ โโโ designTokens.ts # Design system tokens
โ โ
โ โโโ types/ # TypeScript types
โ โ โโโ index.ts
โ โ โโโ PlayerData.ts
โ โ โโโ BackendStatus.ts
โ โ โโโ SummarySection.ts
โ โ
โ โโโ utils/ # Utility functions
โ โ โโโ playerProfileStorage.ts
โ โ
โ โโโ App.tsx # Root component
โ โโโ App.css
โ โโโ main.tsx # Entry point
โ โโโ index.css
โ
โโโ docs/ # Documentation
โ โโโ ARCHITECTURE.md
โ โโโ DESIGN_SYSTEM.md
โ โโโ VoiceInFogUIFlow.md
โ โโโ Faultlines.md
โ โโโ ... (various feature docs)
โ
โโโ .env # Environment variables
โโโ .gitignore
โโโ eslint.config.js
โโโ index.html
โโโ package.json
โโโ tsconfig.json
โโโ tsconfig.app.json
โโโ tsconfig.node.json
โโโ vite.config.ts
โโโ vitest.config.ts
โโโ README.md
| Directory | Purpose | Example Files |
|---|---|---|
/features/* |
Feature modules (Clean Architecture) | Echoes, Patterns, Faultlines |
/components/ui |
Reusable UI primitives | Button, Card, Input |
/services |
API communication | Backend API wrapper |
/store |
Global state management | Zustand stores |
/types |
TypeScript type definitions | Interfaces, types |
/styles |
Global styles and theme | Design tokens, theme |
/hooks |
Custom React hooks | usePlayerData, useCachedQuery |
/pages |
Top-level page components | Dashboard, Onboarding |
Contributions are welcome! Here's how to get started:
- Check existing issues first
- Use issue templates
- Provide detailed reproduction steps
- Include screenshots/videos if applicable
-
Fork the repository
git clone https://github.com/YOUR_USERNAME/LegendScope.git
-
Create a feature branch
git checkout -b feature/amazing-feature
-
Make your changes
- Follow existing code style
- Use design tokens for styling
- Write TypeScript with strict mode
- Add tests for new features
- Update documentation
-
Commit with conventional commits
git commit -m "feat: Add amazing feature" git commit -m "fix: Resolve bug in component" git commit -m "docs: Update README"
-
Push and create PR
git push origin feature/amazing-feature
- TypeScript: Use strict mode, avoid
any - React: Functional components with hooks
- Styling: Use design tokens, follow 8px grid
- Naming: PascalCase for components, camelCase for functions
- Files: One component per file, co-locate styles
- Write unit tests for business logic
- Test edge cases and error states
- Aim for >80% coverage on critical paths
This project is licensed under the MIT License - see the LICENSE file for details.
- Riot Games - For the League of Legends API
- Community Data Dragon - For champion assets
- React Community - For amazing libraries and tools
- League of Legends Players - For inspiration and feedback
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Email: [email protected] (replace with actual contact)
If you find LegendScope useful, give it a โญ๏ธ on GitHub!
Built with โค๏ธ for the League of Legends community
LegendScope is not endorsed by Riot Games and does not reflect the views or opinions of Riot Games or anyone officially involved in producing or managing League of Legends. League of Legends and Riot Games are trademarks or registered trademarks of Riot Games, Inc.