diff --git a/docs/runner-display-alternatives.md b/docs/runner-display-alternatives.md new file mode 100644 index 0000000..661bf32 --- /dev/null +++ b/docs/runner-display-alternatives.md @@ -0,0 +1,204 @@ +# Runner Display Alternatives - Design Proposals + +## Current Implementation Issues +- Baseball diamond is visually cluttered +- Runners are represented by small numbered circles that are hard to see +- Player information is not immediately accessible +- Takes up significant vertical space +- Doesn't provide quick access to runner card details +- UX is confusing - users want to quickly glance at cards for each runner + +## Design Goals +- **Glanceable**: See runner status instantly without searching +- **Compact**: Use less vertical space (mobile-first) +- **Card Access**: Quick access to view runner player cards +- **Clear State**: Immediately obvious which bases are occupied +- **Professional**: Modern, polished appearance + +--- + +## Option 1: Horizontal Runner Card Bar + +### Visual Description +A sleek horizontal bar showing 3 slots (1st, 2nd, 3rd) with mini player cards that expand on tap/click. + +``` +┌────────────────────────────────────────────────────────┐ +│ RUNNERS ON BASE │ +│ ┌──────┐ ┌──────┐ ┌──────┐ │ +│ │ 1B │ │ 2B │ │ 3B │ │ +│ │ ──── │ │[IMG] │ │ ──── │ │ +│ │ │ │ J.D. │ │ │ │ +│ │ Empty│ │ │ │ Empty│ │ +│ └──────┘ └──────┘ └──────┘ │ +└────────────────────────────────────────────────────────┘ +``` + +### Features +- **Empty State**: Gray/muted card with dashed border and "Empty" text +- **Occupied State**: Player headshot, name, and team color border +- **Tap to Expand**: Shows full player card modal +- **Visual Hierarchy**: Occupied bases use team colors and are visually prominent +- **Badge Indicator**: Small circular badge with base number (1/2/3) on top-right + +### Pros +- ✅ Very compact (single row) +- ✅ Clear visual distinction between empty/occupied +- ✅ Easy touch targets for mobile +- ✅ Horizontally balanced layout +- ✅ Player images make it personal/engaging + +### Cons +- ❌ May be cramped on very small screens +- ❌ Requires good player headshots for best effect + +### CSS Approach +- Grid layout with 3 equal columns +- Card-style mini containers +- Smooth hover/tap states with scale transform +- Team color accent on occupied cards + +--- + +## Option 2: Compact Diamond Indicator Strip + +### Visual Description +Minimalist strip showing bases as dots/indicators with runner names inline. + +``` +┌────────────────────────────────────────────────────────┐ +│ ○ 1B Empty ● 2B J. Doe (#24) ○ 3B Empty │ +│ Tap any runner to view card │ +└────────────────────────────────────────────────────────┘ +``` + +### Features +- **Dot Indicators**: Hollow circle = empty, filled circle = occupied +- **Inline Text**: Base label + player name (abbreviated) + jersey number +- **Color Coding**: Dot and text use team color when occupied +- **Single Line**: Extremely compact +- **Hover State**: Underline runner names, show "tap to view card" tooltip + +### Pros +- ✅ Absolute minimal space usage +- ✅ Text-based, works without images +- ✅ Extremely fast to scan +- ✅ Works well in both light/dark mode + +### Cons +- ❌ Less visually engaging +- ❌ No player images visible +- ❌ May feel too minimal/plain +- ❌ Harder to tap on mobile (smaller targets) + +### CSS Approach +- Flexbox with space-between +- Dot using ::before pseudo-element +- Text truncation for long names +- Underline decoration on hover/active + +--- + +## Option 3: Stacked Runner Cards (Recommended) + +### Visual Description +Card-based interface showing only occupied bases as expandable cards in a horizontal stack. Empty bases are represented by small placeholder chips. + +``` +┌────────────────────────────────────────────────────────┐ +│ RUNNERS ON BASE │ +│ │ +│ 1B: ─ 2B: [Card] 3B: ─ │ +│ ┌──────────┐ │ +│ │ [IMG] │ │ +│ │ J. Doe │ │ +│ │ #24 2B │ │ +│ │ [View] │ │ +│ └──────────┘ │ +└────────────────────────────────────────────────────────┘ +``` + +### Features +- **Empty Bases**: Small chip/badge showing "1B: —" (muted, minimal) +- **Occupied Bases**: Full mini card with: + - Player headshot (circular) + - Player name (bold) + - Jersey number + position + - Team color accent/border + - "View Card" button +- **Responsive**: Cards stack vertically on narrow screens +- **Visual Priority**: Occupied bases are much larger and more prominent +- **Quick Actions**: Button directly on card for instant access + +### Pros +- ✅ Best balance of compact + informative +- ✅ Only shows detail where needed (occupied bases) +- ✅ Clear call-to-action with "View Card" button +- ✅ Player images add personality +- ✅ Responsive layout adapts well to mobile +- ✅ Professional, modern card-based UI pattern + +### Cons +- ❌ Slightly more vertical space when bases loaded +- ❌ Requires player headshots for best experience + +### CSS Approach +- Flexbox/Grid hybrid (flex-wrap for responsive) +- Empty bases: inline-flex badge (h-8, minimal) +- Occupied bases: w-32 card with padding +- Shadow and border-radius for card depth +- Team color as left border accent (4px) + +### Implementation Details +```vue +
+ +
+ 1B: + +
+ + +
+ +
+

{{ player.name }}

+

#{{ player.jersey }} • 2B

+
+ +
+
+``` + +--- + +## Recommendation: Option 3 (Stacked Runner Cards) + +### Why This Is Best +1. **Optimizes for the common case**: Most at-bats have 0-1 runners, so minimizing empty state is key +2. **Mobile-first**: Large tap targets, clear hierarchy, easy to use one-handed +3. **Information density**: Shows exactly what's needed without clutter +4. **Modern UX**: Card-based pattern is familiar and professional +5. **Scalable**: Works equally well with 1, 2, or 3 runners on base + +### Responsive Behavior +- **Mobile (< 640px)**: Stack cards vertically, full width +- **Tablet (640-1024px)**: Horizontal row, cards side-by-side +- **Desktop (> 1024px)**: Same as tablet, more breathing room + +### Accessibility +- Semantic HTML with proper ARIA labels +- Keyboard navigation support +- High contrast for empty vs occupied states +- Screen reader announces "Runner on second base: J. Doe, number 24" + +--- + +## Next Steps +1. Choose preferred option (or hybrid approach) +2. Create Vue component implementation +3. Test on mobile devices +4. Gather user feedback +5. Iterate based on real gameplay usage diff --git a/docs/runner-display-mockups.html b/docs/runner-display-mockups.html new file mode 100644 index 0000000..9ce30d6 --- /dev/null +++ b/docs/runner-display-mockups.html @@ -0,0 +1,625 @@ + + + + + + Runner Display Mockups - Options 1, 3, & 4 + + + + +
+ +
+

Runner Display Mockups

+

Interactive mockups of Options 1, 3, and 4 for runners on base display

+
+ + +
+

Test Scenarios

+
+ + + + +
+
+ + +
+
+

Option 1: Horizontal Runner Card Bar

+

Three equal-width cards showing all bases with equal visual weight

+
+ +
+

Runners on Base

+ + + + + +
+ +
+
+ + +
+
+

✅ Pros

+
    +
  • • Very compact (single row)
  • +
  • • Clear visual distinction
  • +
  • • Easy touch targets
  • +
  • • Balanced layout
  • +
+
+
+

❌ Cons

+
    +
  • • Always shows all 3 cards
  • +
  • • May feel cluttered when bases empty
  • +
  • • Less visual hierarchy
  • +
+
+
+
+ + +
+
+

Option 3: Stacked Runner Cards

+

Only occupied bases get prominent cards, empty bases are minimal chips

+
+ +
+

Runners on Base

+ +
+ +
+
+ + +
+
+

✅ Pros

+
    +
  • • Optimizes for common case (0-1 runners)
  • +
  • • Clear visual hierarchy
  • +
  • • Easy card access with button
  • +
  • • Mobile-first design
  • +
  • • Professional card-based UI
  • +
+
+
+

❌ Cons

+
    +
  • • More horizontal space with 3 runners
  • +
  • • Requires player headshots
  • +
+
+
+
+ + +
+
+

+ Option 4: Expanding Runner Cards with Matchup + NEW RECOMMENDATION +

+

+ Runners list on left, catcher on right. Click a runner to expand it in place and show full card + catcher matchup. + Only visible when runners on base. +

+
+ + +
+ +
+ +
+

Runners on Base

+ +
+ +
+ + + +
+ + +
+

Catcher

+ + +
+
+
+ +
+
+
Buster Posey
+
#28 • C
+
+
+
+ Click a runner to see matchup → +
+
+ + + +
+
+
+ + +
+
+

✅ Pros

+
    +
  • Expands in place - no jarring screen flip
  • +
  • Smooth transition - runner card grows to show full player card
  • +
  • • Catcher card appears simultaneously for matchup context
  • +
  • • Only shows when needed (on_base_code > 0)
  • +
  • • Consistent with pitcher vs batter styling
  • +
  • • Clear visual hierarchy
  • +
+
+
+

❌ Cons

+
    +
  • • Requires extra click to see full cards
  • +
  • • Slightly more complex animation
  • +
+
+
+ + +
+

💡 Implementation Notes

+
    +
  • • Component only renders when thisPlay.on_base_code > 0
  • +
  • • Default: Runners list (left) with compact cards + Catcher summary (right)
  • +
  • • Click runner → Runner card expands in place to show full player card
  • +
  • • Simultaneously, catcher card expands to show full matchup
  • +
  • • Click again or click another runner to collapse/switch
  • +
  • • Smooth height transition using CSS max-height animation
  • +
+
+
+ + +
+

Final Recommendation: Option 4

+
+

🎯 Smooth in-place expansion - Runner card grows to reveal full player card

+

🔄 Integrated matchup view - Catcher card appears alongside for comparison

+

👁️ No screen flipping - Everything expands/collapses in the same layout

+

📱 Mobile-first design - Works seamlessly on all screen sizes

+

Strategic context - See runner vs catcher for steal decisions

+

Clean UX - Compact by default, detailed on demand

+
+
+
+ + + + diff --git a/frontend-sba/components/Game/GamePlay.vue b/frontend-sba/components/Game/GamePlay.vue index 72849e9..4798ad7 100644 --- a/frontend-sba/components/Game/GamePlay.vue +++ b/frontend-sba/components/Game/GamePlay.vue @@ -79,6 +79,16 @@ :pitcher-team-abbrev="pitcherTeamAbbrev" /> + + + + + + { : gameState.value.away_team_abbrev ?? '' }) +// Team colors for runner/catcher matchup display +const battingTeamColor = computed(() => { + if (!gameState.value) return '#3b82f6' + // Use home team dice color when home team is batting, otherwise use a default blue + return gameState.value.half === 'bottom' + ? `#${gameState.value.home_team_dice_color}` + : '#3b82f6' +}) + +const fieldingTeamColor = computed(() => { + if (!gameState.value) return '#10b981' + // Use home team dice color when home team is fielding, otherwise use a default green + return gameState.value.half === 'top' + ? `#${gameState.value.home_team_dice_color}` + : '#10b981' +}) + // Local UI state const isLoading = ref(true) const connectionStatus = ref<'connecting' | 'connected' | 'disconnected'>('connecting') diff --git a/frontend-sba/components/Game/RunnerCard.vue b/frontend-sba/components/Game/RunnerCard.vue new file mode 100644 index 0000000..1fe5f7c --- /dev/null +++ b/frontend-sba/components/Game/RunnerCard.vue @@ -0,0 +1,187 @@ + + + + + diff --git a/frontend-sba/components/Game/RunnersOnBase.vue b/frontend-sba/components/Game/RunnersOnBase.vue new file mode 100644 index 0000000..ff4e859 --- /dev/null +++ b/frontend-sba/components/Game/RunnersOnBase.vue @@ -0,0 +1,206 @@ + + + + +