docs: add comprehensive precision controls documentation for Know Your World

Add detailed documentation for the advanced precision control system that makes sub-pixel regions (Gibraltar 0.08px, Jersey 0.82px) clickable:

- PRECISION_CONTROLS.md: Complete technical deep-dive
  - Automatic cursor dampening (3-25% speed based on region size)
  - Auto super-zoom (up to 60x) after 500ms hover on sub-pixel regions
  - Quick-escape mechanism (>50px/frame cancels all precision features)
  - Crosshair accuracy fix ensuring dampened cursor matches hover highlighting
  - Configuration constants, debug logging, performance considerations

- know-your-world/README.md: Game overview and feature documentation
  - Game modes, maps, difficulty levels, study mode
  - Visual features, technical architecture, component structure
  - Development guide, troubleshooting, configuration

- Updated documentation graph:
  - Main README → Arcade Games → Know Your World → Precision Controls
  - All documentation now reachable from root README

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock 2025-11-19 08:21:27 -06:00
parent 3bf127f344
commit 8511998d0c
4 changed files with 546 additions and 0 deletions

View File

@ -804,6 +804,23 @@ MIT License - see LICENSE file for details.
## 📚 Additional Documentation
### Arcade Game System
**Location**: [`apps/web/src/arcade-games/`](./apps/web/src/arcade-games/)
**Overview**: [`apps/web/src/arcade-games/README.md`](./apps/web/src/arcade-games/README.md)
Modular, plugin-based architecture for building multiplayer arcade games with real-time synchronization.
**Available Games**:
- **[Know Your World](./apps/web/src/arcade-games/know-your-world/README.md)** - Geography quiz with precision controls for tiny regions ([Precision Controls Docs](./apps/web/src/arcade-games/know-your-world/PRECISION_CONTROLS.md))
- Number Guesser - Hot/cold guessing game
- Memory Quiz - Pattern matching challenge
- Matching Pairs - Memory card game
**Key Documentation**:
- **[Game SDK](./apps/web/src/arcade-games/README.md)** - How to create new arcade games
- **[Precision Controls](./apps/web/src/arcade-games/know-your-world/PRECISION_CONTROLS.md)** - Advanced cursor dampening and super zoom system
### Worksheet Generator
**Location**: [`apps/web/src/app/create/worksheets/`](./apps/web/src/app/create/worksheets/)

View File

@ -15,6 +15,25 @@ A modular, plugin-based architecture for building multiplayer arcade games with
---
## Available Games
### Know Your World
**Location**: [`know-your-world/`](./know-your-world/)
**Documentation**: [`know-your-world/README.md`](./know-your-world/README.md)
A geography quiz game where players identify countries, states, and territories on unlabeled maps.
**Key Features**:
- **[Precision Controls](./know-your-world/PRECISION_CONTROLS.md)** - Automatic cursor dampening and super zoom for tiny regions (Gibraltar 0.08px)
- **3 Game Modes**: Cooperative, Race, Turn-Based
- **Multiple Maps**: World (256 countries), USA States (51 states)
- **Adaptive Difficulty**: Per-map difficulty tiers with smart filtering
- **Study Mode**: Optional memorization period before gameplay
- **Visual Features**: Excluded region visualization, adaptive zoom magnifier, smart label positioning
---
## Overview
### Goals

View File

@ -0,0 +1,291 @@
# Precision Controls for Tiny Map Regions
## Overview
The Know Your World map includes sophisticated precision controls that automatically activate when hovering over extremely small regions, making it possible to accurately select sub-pixel regions like Gibraltar (0.08px) and Jersey (0.82px) on screen.
## Features
### 1. Automatic Cursor Dampening (Precision Mode)
**Purpose**: Slow down cursor movement when over tiny regions for more precise control
**Activation**: Automatically detects when hovering over small regions (< 15px)
**Behavior**:
- **Sub-pixel regions (< 1px)**: 3% cursor speed (ultra precision)
- Example: Gibraltar (0.08px width)
- **Tiny regions (1-5px)**: 10% cursor speed (high precision)
- Example: Jersey (0.82px width)
- **Small regions (5-15px)**: 25% cursor speed (moderate precision)
- Example: Rhode Island (~11px)
**Visual feedback**: Cursor changes to crosshair when precision mode is active
**Implementation**: `MapRenderer.tsx` lines 166-187, 668-712
```typescript
// Adaptive dampening based on smallest region size
const getDampeningFactor = (size: number): number => {
if (size < 1) return 0.03 // Ultra precision
if (size < 5) return 0.1 // High precision
return 0.25 // Moderate precision
}
// Apply dampening by interpolating cursor position
const deltaX = cursorX - lastCursorRef.current.x
const deltaY = cursorY - lastCursorRef.current.y
finalCursorX = lastCursorRef.current.x + deltaX * dampeningFactor
finalCursorY = lastCursorRef.current.y + deltaY * dampeningFactor
```
### 2. Auto Super-Zoom on Hover
**Purpose**: Dramatically increase magnification for sub-pixel regions after a brief hover
**Activation**:
- Automatically triggers after **500ms** of hovering over sub-pixel regions (< 1px)
- Only activates when magnifier is already showing
**Behavior**:
- Normal adaptive zoom: 8-24x
- Super zoom: up to **60x magnification** (2.5x multiplier)
- Applies to regions smaller than 1 screen pixel
**Visual feedback**:
- Magnifier border changes from **blue** to **gold**
- Gold glow shadow around magnifier
- Zoom level indicator shows current magnification
**Implementation**: `MapRenderer.tsx` lines 853-873, 1282-1292
```typescript
const HOVER_DELAY_MS = 500
const SUPER_ZOOM_MULTIPLIER = 2.5
// Start timer when hovering over sub-pixel regions
if (detectedSmallestSize < 1 && shouldShow && !superZoomActive) {
hoverTimerRef.current = setTimeout(() => {
setSuperZoomActive(true)
}, HOVER_DELAY_MS)
}
// Apply super zoom multiplier to adaptive zoom
if (superZoomActive) {
adaptiveZoom = Math.min(60, adaptiveZoom * SUPER_ZOOM_MULTIPLIER)
}
```
### 3. Quick-Escape Mechanism
**Purpose**: Allow users to instantly cancel precision mode and super zoom with fast mouse movement
**Activation**: Moving mouse faster than **50 pixels per frame**
**Behavior**:
- Immediately cancels cursor dampening
- Immediately cancels super zoom
- Clears hover timer if active
- Restores normal cursor speed
**Visual feedback**:
- Cursor returns to normal pointer
- Magnifier border returns to blue (if still showing)
- Super zoom deactivates
**Implementation**: `MapRenderer.tsx` lines 641-665
```typescript
const QUICK_MOVE_THRESHOLD = 50 // pixels per frame
// Calculate velocity
const deltaX = cursorX - lastCursorRef.current.x
const deltaY = cursorY - lastCursorRef.current.y
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY)
velocity = distance
// Quick escape on fast movement
if (velocity > QUICK_MOVE_THRESHOLD) {
setPrecisionMode(false)
setSuperZoomActive(false)
clearTimeout(hoverTimerRef.current)
}
```
### 4. Crosshair Accuracy
**Purpose**: Ensure crosshairs in magnifier accurately show which region will be selected
**Challenge**: When cursor dampening is active, native mouse events fire at real mouse position, but crosshairs show dampened position - creating a mismatch
**Solution**: Manual region detection using dampened cursor position
**Implementation**: `MapRenderer.tsx` lines 743-842
```typescript
// Convert dampened cursor to client coordinates
const finalClientX = containerRect.left + finalCursorX
const finalClientY = containerRect.top + finalCursorY
// Check which region is under dampened cursor
const cursorInRegion =
finalClientX >= regionLeft &&
finalClientX <= regionRight &&
finalClientY >= regionTop &&
finalClientY <= regionBottom
// Find closest region by distance to center
if (cursorInRegion) {
const distanceToCenter = Math.sqrt(
Math.pow(finalClientX - regionCenterX, 2) +
Math.pow(finalClientY - regionCenterY, 2)
)
if (distanceToCenter < smallestDistanceToCenter) {
regionUnderCursor = region.id
}
}
// Set hover state manually (bypass native events)
setHoveredRegion(regionUnderCursor)
```
**Native hover events disabled**: When precision mode is active, native `onMouseEnter`/`onMouseLeave` are bypassed:
```typescript
onMouseEnter={() => !precisionMode && setHoveredRegion(region.id)}
onMouseLeave={() => !precisionMode && setHoveredRegion(null)}
```
## User Experience Flow
### Example: Selecting Gibraltar (0.08px)
1. **Hover over Iberian Peninsula area**
- Magnifier appears showing 8-12x zoom
- Cursor speed normal
2. **Move cursor near Gibraltar**
- **Precision mode activates**: Cursor becomes crosshair
- **Cursor dampening**: Movement slows to 3% speed
- User has fine control to position cursor
3. **Hold cursor over Gibraltar for 500ms**
- **Super zoom activates**: Magnifier zooms to 40-60x
- **Magnifier border**: Changes from blue to gold
- Gibraltar now clearly visible and selectable
4. **Click on Gibraltar** or **"shake" mouse to escape**
- Quick movement (>50px/frame) instantly cancels precision mode
- Cursor returns to normal speed
- Magnifier returns to blue border (or hides if moved away)
## Debug Logging
Extensive console logging helps troubleshoot precision controls:
```javascript
// Precision mode activation
console.log('[Precision Mode] ✅ DAMPENING ACTIVE:', {
smallestRegionSize: '0.82px',
dampeningFactor: '10%',
actual: { x: 500, y: 300 },
dampened: { x: 485, y: 298 }
})
// Super zoom activation
console.log('[Super Zoom] 🔍 ACTIVATING super zoom!')
// Quick escape
console.log('[Quick Escape] 💨 Fast movement detected (75px) - canceling')
// Hover detection
console.log('[Hover Detection] Region under dampened cursor:', {
region: 'je',
regionName: 'Jersey',
dampenedPos: { x: 485, y: 298 },
distanceToCenter: '2.5px'
})
```
## Configuration Constants
All tuning parameters are defined at the top of `MapRenderer.tsx`:
```typescript
// Hover delay before super zoom activates
const HOVER_DELAY_MS = 500
// Velocity threshold for quick-escape (pixels per frame)
const QUICK_MOVE_THRESHOLD = 50
// Super zoom multiplier (applied to adaptive zoom)
const SUPER_ZOOM_MULTIPLIER = 2.5
// Adaptive dampening factors
const getDampeningFactor = (size: number): number => {
if (size < 1) return 0.03 // Ultra precision: 3% speed
if (size < 5) return 0.1 // High precision: 10% speed
return 0.25 // Moderate precision: 25% speed
}
// Maximum zoom levels
const MAX_ZOOM_NORMAL = 24 // Normal adaptive zoom cap
const MAX_ZOOM_SUPER = 60 // Super zoom cap
```
## Technical Details
### Coordinate Systems
The implementation handles three coordinate systems:
1. **Container coordinates**: Relative to map container div (includes padding)
2. **Client coordinates**: Absolute screen position
3. **SVG coordinates**: ViewBox coordinate space for rendering
Cursor dampening happens in container coordinates, then converts to client coordinates for region detection.
### Performance Considerations
- **No performance impact when inactive**: All precision features only run when hovering over map
- **Efficient region detection**: Uses `getBoundingClientRect()` which is hardware-accelerated
- **Minimal state updates**: Only updates when cursor moves or regions change
- **Spring animations**: Uses `@react-spring/web` for smooth magnifier transitions
### Browser Compatibility
Works in all modern browsers that support:
- CSS transforms
- getBoundingClientRect()
- React 18 hooks
- @react-spring/web
Tested on:
- Chrome/Edge (Chromium)
- Firefox
- Safari
## Future Improvements
Potential enhancements:
1. **Configurable sensitivity**: Let users adjust dampening factors in settings
2. **Haptic feedback**: Vibration on mobile when precision mode activates
3. **Audio cues**: Subtle sound when super zoom activates
4. **Visual trail**: Show cursor path in dampened mode
5. **Gamepad support**: Use analog stick for dampened cursor control
6. **Keyboard navigation**: Arrow keys for pixel-perfect positioning
## Related Files
- `MapRenderer.tsx` - Main implementation
- `PlayingPhase.tsx` - Passes props to MapRenderer
- `maps.ts` - Map data and region metadata
- `types.ts` - TypeScript interfaces
## See Also
- [Map Rendering Architecture](./MAP_RENDERING.md) (if exists)
- [Game Configuration](./GAME_CONFIG.md) (if exists)
- [Difficulty System](./DIFFICULTY.md) (if exists)

View File

@ -0,0 +1,219 @@
# Know Your World
A geography quiz game where players identify countries, states, and territories on unlabeled maps.
## Features
### Game Modes
- **Cooperative**: Work together as a team to find all regions
- **Race**: Compete to click regions first
- **Turn-Based**: Take turns finding locations
### Maps
- **World Map**: 256 countries and territories
- Filter by continent: Africa, Asia, Europe, North America, South America, Oceania, Antarctica
- **USA States**: 51 states (50 states + DC)
### Difficulty Levels
Configurable per map with customizable difficulty tiers:
- **World Map**: Easy (capitals only), Medium, Hard (all countries), Expert (including tiny territories)
- **USA States**: Easy (large states), Hard (all states including small ones)
### Study Mode
Optional study period before gameplay:
- Skip (no study time)
- 30 seconds (quick review)
- 1 minute (study time)
- 2 minutes (deep study)
During study, all regions are labeled so players can memorize locations.
## Precision Controls for Tiny Regions
One of the most innovative features is the **automatic precision control system** that makes it possible to click on extremely small regions like Gibraltar (0.08px) and Jersey (0.82px).
### Features:
- **Adaptive cursor dampening**: Automatically slows cursor movement (3-25% speed) when over tiny regions
- **Auto super-zoom**: Zooms up to 60x after hovering 500ms over sub-pixel regions
- **Quick-escape**: Fast mouse movement instantly cancels precision features
- **Crosshair accuracy**: Magnifier crosshairs accurately show which region will be selected
**📖 See [PRECISION_CONTROLS.md](./PRECISION_CONTROLS.md) for complete documentation**
## Visual Features
### Excluded Region Visualization
Regions filtered out by difficulty settings are pre-labeled on the map in gray, showing which regions are not included in the current game.
### Enhanced Contrast
- Unfound regions: 70% opacity (increased from 30% for better visibility)
- Found regions: 100% opacity with player avatar pattern
- Excluded regions: Gray fill with label
### Adaptive Zoom Magnifier
Shows a magnified view (8-60x) when hovering over crowded or tiny regions:
- Automatically calculates optimal zoom based on region density and size
- Smooth spring animations for position and opacity
- Crosshairs show exact cursor position
- Dashed box on main map shows magnified area
### Smart Label Positioning
Uses D3 force simulation to position region labels without overlaps:
- Regular regions: Labels at center
- Small regions: Labels with arrow pointers
- Washington DC: Special positioning to avoid blocking other states
- Collision detection prevents label overlaps
## Technical Architecture
### Component Structure
```
know-your-world/
├── components/
│ ├── GameComponent.tsx # Main game container
│ ├── SetupPhase.tsx # Game configuration screen
│ ├── StudyPhase.tsx # Optional study mode
│ ├── PlayingPhase.tsx # Active gameplay
│ ├── ResultsPhase.tsx # Game completion screen
│ ├── MapRenderer.tsx # SVG map rendering + precision controls
│ ├── ContinentSelector.tsx # Interactive world map continent filter
│ └── MapRenderer.stories.tsx # Storybook stories
├── Provider.tsx # React Context provider
├── Validator.ts # Server-side game logic
├── index.ts # Game definition export
├── types.ts # TypeScript interfaces
├── maps.ts # Map data (World, USA)
├── continents.ts # Continent definitions
├── mapColors.ts # Color utilities
└── README.md # This file
```
### State Management
Uses React Context (`KnowYourWorldProvider`) for client-side state:
- Game phase (setup, study, playing, results)
- Selected map and continent
- Game mode and difficulty
- Current prompt and regions found
- Guess history and player metadata
### Server Validation
All game moves are validated server-side in `Validator.ts`:
- Verifies region IDs are valid
- Checks if region was already found
- Tracks which player found each region
- Handles turn order (turn-based mode)
- Generates random prompts
### Map Data
Maps are sourced from `@svg-maps/world` and `@svg-maps/usa` with enhancements:
- Pre-calculated bounding boxes for each region
- Center coordinates for labels
- Continent metadata (world map only)
- Difficulty tier assignments
## Configuration
Game configuration is persisted in arcade room settings:
```typescript
interface KnowYourWorldConfig {
selectedMap: 'world' | 'usa'
gameMode: 'cooperative' | 'race' | 'turn-based'
difficulty: string // Difficulty level ID (varies per map)
studyDuration: 0 | 30 | 60 | 120 // seconds
selectedContinent: 'all' | ContinentId // world map only
}
```
## Development
### Adding New Maps
1. Install or create SVG map data package
2. Add map data to `maps.ts`:
```typescript
export const MAP_DATA = {
'new-map': {
name: 'New Map',
regions: [...],
viewBox: '0 0 1000 1000',
// ...
}
}
```
3. Add difficulty configuration
4. Update type definitions
### Customizing Difficulty
Edit `maps.ts` to add custom difficulty tiers:
```typescript
difficultyConfig: {
levels: [
{ id: 'easy', label: 'Easy', emoji: '😊', description: 'Large regions only' },
{ id: 'hard', label: 'Hard', emoji: '🤔', description: 'All regions' },
],
tiers: {
easy: { minWidth: 15, minHeight: 15, minArea: 200 },
hard: { minWidth: 0, minHeight: 0, minArea: 0 },
}
}
```
### Testing
Use Storybook to test map rendering:
```bash
npm run storybook
```
Navigate to "Arcade Games / Know Your World / Map Renderer"
## Troubleshooting
### Tiny regions not clickable
- Check browser zoom level (100% recommended)
- Ensure precision controls are working (look for crosshair cursor)
- Check console for debug logs
### Labels overlapping
- Adjust force simulation parameters in `MapRenderer.tsx`:
- `centeringStrength`: How strongly labels pull toward region centers
- `collisionPadding`: Minimum space between labels
- `simulationIterations`: More iterations = better layout
### Performance issues
- Reduce map size (filter by continent)
- Lower difficulty (fewer regions)
- Disable label arrows in force tuning parameters
## Related Documentation
- [Precision Controls](./PRECISION_CONTROLS.md) - Cursor dampening and super zoom
- [Game SDK](../../lib/arcade/README.md) - How arcade games are structured
- [Arcade System](../../app/arcade/README.md) - Overall arcade architecture
## Credits
- Map data: [@svg-maps/world](https://www.npmjs.com/package/@svg-maps/world), [@svg-maps/usa](https://www.npmjs.com/package/@svg-maps/usa)
- Label positioning: [D3 Force](https://d3js.org/d3-force)
- Animations: [React Spring](https://www.react-spring.dev/)