---
name: board-game-ui
description: UI/UX design for digital board games. Use when building game interfaces, implementing drag-and-drop, rendering game boards, showing player information, handling animations, or designing responsive layouts. Covers Canvas, SVG, and DOM-based approaches.
---
# Board Game UI Skill
## Overview
This skill provides expertise for building user interfaces for digital board games. It covers rendering approaches (DOM, Canvas, SVG), interaction patterns (drag-and-drop, click-to-select), responsive design for different screen sizes, and UX principles specific to turn-based games.
## Rendering Approaches
### When to Use Each
| Approach | Best For | Avoid When |
|----------|----------|------------|
| **DOM/CSS** | Card games, simple boards, UI overlays | Many moving pieces, complex animations |
| **SVG** | Maps, vector graphics, zoomable boards | Thousands of elements, pixel effects |
| **Canvas** | Complex animations, particles, real-time | Accessibility needed, text-heavy |
| **Hybrid** | Most board games | Over-engineering simple games |
### Recommended: Hybrid Approach
Use DOM for UI chrome (menus, player info, cards) and Canvas/SVG for the game board:
```html
```
## Layout Patterns
### Responsive Game Layout
```css
.game-container {
display: grid;
height: 100vh;
gap: 1rem;
padding: 1rem;
/* Desktop: sidebar layout */
grid-template-columns: 250px 1fr;
grid-template-rows: 1fr auto;
grid-template-areas:
"sidebar board"
"sidebar actions";
}
/* Tablet: stack sidebar above */
@media (max-width: 1024px) {
.game-container {
grid-template-columns: 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"sidebar"
"board"
"actions";
}
.player-panel {
display: flex;
overflow-x: auto;
}
}
/* Mobile: minimal chrome */
@media (max-width: 600px) {
.game-container {
padding: 0.5rem;
gap: 0.5rem;
}
.player-panel {
font-size: 0.875rem;
}
}
```
### Aspect Ratio Preservation
```css
.board-area {
grid-area: board;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
#game-board {
max-width: 100%;
max-height: 100%;
aspect-ratio: 5 / 4; /* Match your board dimensions */
}
```
## SVG Game Board
### Board Structure
```html
```
### Interactive Elements
```javascript
// Click handling on SVG elements
document.getElementById('game-board').addEventListener('click', (e) => {
const route = e.target.closest('.route');
const city = e.target.closest('.city');
const token = e.target.closest('.ship-token');
if (route) {
handleRouteClick(route.dataset.routeId);
} else if (city) {
handleCityClick(city.dataset.cityId);
} else if (token) {
handleTokenClick(token.dataset.shipId);
}
});
// Hover effects
function setupHoverEffects() {
document.querySelectorAll('.route').forEach(route => {
route.addEventListener('mouseenter', () => {
route.classList.add('highlighted');
showRouteTooltip(route.dataset.routeId);
});
route.addEventListener('mouseleave', () => {
route.classList.remove('highlighted');
hideTooltip();
});
});
}
```
```css
/* SVG hover/selection states */
.route {
cursor: pointer;
transition: stroke 0.2s, stroke-width 0.2s;
}
.route:hover,
.route.highlighted {
stroke: #4a9eff;
stroke-width: 12;
}
.route.claimed {
stroke: var(--claiming-player-color);
}
.route.unavailable {
opacity: 0.3;
pointer-events: none;
}
.city:hover circle {
fill: #555;
transform: scale(1.1);
}
```
## Drag and Drop
### HTML5 Drag and Drop (for cards/tiles)
```javascript
// Make elements draggable
function setupDraggable(element, type, id) {
element.draggable = true;
element.addEventListener('dragstart', (e) => {
e.dataTransfer.setData('application/json', JSON.stringify({ type, id }));
e.dataTransfer.effectAllowed = 'move';
element.classList.add('dragging');
});
element.addEventListener('dragend', () => {
element.classList.remove('dragging');
clearDropTargets();
});
}
// Make slots accept drops
function setupDropTarget(element, acceptTypes, onDrop) {
element.addEventListener('dragover', (e) => {
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
element.classList.add('drop-target');
});
element.addEventListener('dragleave', () => {
element.classList.remove('drop-target');
});
element.addEventListener('drop', (e) => {
e.preventDefault();
element.classList.remove('drop-target');
const data = JSON.parse(e.dataTransfer.getData('application/json'));
if (acceptTypes.includes(data.type)) {
onDrop(data);
}
});
}
```
### Click-to-Select Alternative
For touch devices and accessibility:
```javascript
let selectedItem = null;
function handleItemClick(item) {
if (selectedItem === item) {
// Deselect
deselectItem();
} else if (selectedItem) {
// Try to place selected item
if (canPlaceAt(selectedItem, item)) {
placeItem(selectedItem, item);
}
deselectItem();
} else {
// Select this item
selectItem(item);
}
}
function selectItem(item) {
selectedItem = item;
item.classList.add('selected');
highlightValidTargets(item);
}
function deselectItem() {
if (selectedItem) {
selectedItem.classList.remove('selected');
clearHighlights();
selectedItem = null;
}
}
```
## Player Board UI
### Blueprint Slot Grid
```html
```
```javascript
function startTurnTimer(duration) {
const timerText = document.querySelector('.timer-text');
const timerProgress = document.querySelector('.timer-progress');
let remaining = duration;
const interval = setInterval(() => {
remaining--;
timerText.textContent = remaining;
const percent = (remaining / duration) * 100;
timerProgress.style.strokeDashoffset = 100 - percent;
if (remaining <= 0) {
clearInterval(interval);
}
}, 1000);
return () => clearInterval(interval);
}
```
## Tooltips and Info Panels
```javascript
// Tooltip system
const tooltip = document.getElementById('tooltip');
function showTooltip(content, x, y) {
tooltip.innerHTML = content;
tooltip.style.left = `${x + 10}px`;
tooltip.style.top = `${y + 10}px`;
tooltip.classList.add('visible');
}
function hideTooltip() {
tooltip.classList.remove('visible');
}
// Rich tooltips for game elements
function getTechnologyTooltip(techId) {
const tech = technologies[techId];
return `
${tech.name}
Cost: ${tech.cost} Research
${tech.description}
Unlocks: ${tech.unlocks}
`;
}
```
## Accessibility
### Keyboard Navigation
```javascript
// Make game elements keyboard accessible
document.querySelectorAll('.slot, .card, .route').forEach(el => {
el.setAttribute('tabindex', '0');
el.setAttribute('role', 'button');
el.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
el.click();
}
});
});
```
### Screen Reader Support
```html
```
## Performance Tips
1. **Batch DOM updates** - Use DocumentFragment or requestAnimationFrame
2. **Virtual scrolling** - For long lists (action log, card library)
3. **Lazy load assets** - Load board images for other Ages on demand
4. **Debounce resize handlers** - Don't recalculate layout on every pixel
5. **Use CSS transforms** - For animations instead of top/left
6. **Layer with z-index** - Keep frequently-updated elements on separate layers
## When This Skill Activates
Use this skill when:
- Building game board rendering
- Implementing drag-and-drop interactions
- Designing player board layouts
- Creating card hand displays
- Adding animations and transitions
- Making responsive game layouts
- Improving game accessibility