Commit Graph

12 Commits

Author SHA1 Message Date
Thomas Hallock 53e90414a3 feat: add precision mode system with pixel grid visualization
Add precision mode threshold system for know-your-world magnifier:

**Precision Mode Threshold System:**
- Constant PRECISION_MODE_THRESHOLD = 20 px/px
- Caps zoom when not in pointer lock to prevent exceeding threshold
- Shows clickable notice when threshold reached
- Activates pointer lock for precision control

**Pixel Grid Visualization:**
- Shows gold grid overlay aligned with crosshair
- Each grid cell = 1 screen pixel of mouse movement on main map
- Fades in from 70% to 100% of threshold (14-20 px/px)
- Fades out from 100% to 130% of threshold (20-26 px/px)
- Visible in both normal and precision modes

**Visual "Disabled" State:**
- Magnifier dims (60% brightness, 50% saturation) when at threshold
- Indicates zoom is capped until precision mode activated
- Returns to normal appearance in precision mode

**User Experience:**
- Below 14 px/px: Normal magnifier
- 14-20 px/px: Grid fades in as warning
- At 20 px/px: Full grid, dimmed magnifier, "Click here (not map) for precision mode"
- Click magnifier label (not map) to activate pointer lock
- In precision mode: Grid fades out (20-26 px/px), magnifier returns to normal
- e.stopPropagation() prevents accidental region clicks

**Debug Mode:**
- SHOW_MAGNIFIER_DEBUG_INFO flag (dev only)
- Shows technical info: zoom level and px/px ratio

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-23 14:00:43 -06:00
Thomas Hallock f622bfab54 fix(know-your-world): fix TypeScript build errors
- Fix MapData import in GameInfoPanel.tsx (import from types, not maps)
- Fix MapData import in test files
- Fix currentRegionName type (handle undefined with ?? null)

These errors were blocking the Docker build in CI.
2025-11-23 08:33:56 -06:00
Thomas Hallock 1729418dc5 feat(know-your-world): full-screen layout with squish-through pointer lock escape
Implement full-screen, no-scrolling layout for Know Your World game with seamless
pointer lock UX:

## Layout Changes
- Add react-resizable-panels for vertical panel layout (info top, map bottom)
- Wrap playing phase with StandardGameLayout for 100vh no-scroll behavior
- Extract game info (prompt, progress, error) into compact GameInfoPanel
- Map panel fills remaining space with ResizeObserver for dynamic scaling
- SVG uses aspect-ratio to prevent distortion during panel resize

## Pointer Lock UX
- Remove obtrusive "Enable Precision Controls" prompt entirely
- First click silently enables pointer lock (seamless gameplay)
- Cursor squish-through escape at boundaries:
  - 40px dampen zone: movement slows quadratically near edges
  - 20px squish zone: cursor visually compresses (50%) and stretches (140%)
  - 2px escape threshold: pointer lock releases when squished through
- Custom cursor distortion provides visual feedback for escape progress

## Testing
- Unit tests: GameInfoPanel (20+ tests), PlayingPhase (15+ tests)
- E2E tests: Layout, panel resizing, magnifier behavior
- Update vitest config with Panda CSS aliases

## Technical Details
- ResizeObserver replaces window resize listeners for panel-aware updates
- Labels and magnifier recalculate on panel resize
- All magnifier math preserved (zoom, region indicator, coordinate transforms)
- Boundary dampening uses quadratic easing for natural feel
- Squish effect animates with 0.1s ease-out transition

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 21:50:13 -06:00
Thomas Hallock ab94fd350f fix: use dynamic ES module imports for @svg-maps packages in know-your-world
Fixes production errors where Socket.IO server failed with "Unexpected token 'export'"
when loading map data from @svg-maps/world and @svg-maps/usa packages.

**Changes:**

- **maps.ts**: Use dynamic `import()` for ES modules instead of JSON workaround
  - Async loading via `ensureMapSourcesLoaded()` works in both browser and Node.js
  - Sync Proxy exports (`WORLD_MAP`, `USA_MAP`) for client components
  - Async functions (`getMapData()`, `getFilteredMapData()`) for server-side use
  - Remove JSON data files (world.json, usa.json) - now load directly from npm packages

- **Client components**: Use sync map exports instead of async functions
  - MapRenderer, PlayingPhase, ResultsPhase, SetupPhase, StudyPhase, MapRenderer.stories
  - Import `WORLD_MAP`/`USA_MAP` or use `getFilteredMapDataSync()`
  - No more Promise handling needed in React components

- **Page component**: Disable SSR to prevent build-time errors
  - Use Next.js `dynamic()` import with `ssr: false`
  - Prevents race condition during static generation

- **tsconfig.server.json**: Include maps.ts and related files for server compilation

**Testing:**
-  Docker build succeeds
-  Socket.IO server loads: "Socket server module loaded successfully"
-  Zero ES module errors in production build
-  Maps load correctly from @svg-maps packages via dynamic imports

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 12:16:54 -06:00
Thomas Hallock 0ed4d13db6 fix: move pointer lock management to MapRenderer
**Problem:** Pointer lock was activating on MapRenderer's container,
but PlayingPhase was trying to manage it, so state never updated.

**Solution:** Move all pointer lock management into MapRenderer:
- Add pointerLocked state in MapRenderer
- Add pointer lock event listeners in MapRenderer
- Add click handler to request lock on MapRenderer container
- Add "Enable Precision Controls" overlay in MapRenderer
- Remove all pointer lock code from PlayingPhase

Now pointer lock state tracks correctly and custom cursor will render.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-19 18:06:34 -06:00
Thomas Hallock 5388441ebb fix: increase z-index of pointer lock prompt overlay
Increase z-index from 1000 to 10000 to ensure the overlay
appears above all other content.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-19 18:06:34 -06:00
Thomas Hallock 0dbb2eb83c debug: add logging for pointer lock and custom cursor
Add extensive console logging to debug cursor visibility:

**PlayingPhase:**
- Log when pointer lock listeners attach/detach
- Log pointer lock state changes with element details
- Log container click events with conditions
- Log pointerLocked state changes

**MapRenderer:**
- Log custom cursor render conditions on every render
- Log when cursor should be visible
- Log cursor position when rendering

This will help diagnose why custom cursor isn't visible.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-19 18:06:34 -06:00
Thomas Hallock 749b16ac27 refactor: simplify pointer lock with movement delta multipliers
Major refactoring of precision controls for Know Your World game:

**New Flow:**
- Pointer lock requested once when PlayingPhase mounts (user click)
- Active for entire game session until unmount
- Simpler: use movementX/movementY with adaptive multiplier

**PlayingPhase.tsx:**
- Add pointer lock management with event listeners
- Show "Enable Precision Controls" overlay on mount
- Request pointer lock on first click (user gesture)
- Release on unmount (game ends)
- Pass pointerLocked prop to MapRenderer

**MapRenderer.tsx:**
- Accept pointerLocked as prop (don't manage internally)
- Remove complex cursor dampening (dual refs: raw vs dampened)
- Simplified: apply multiplier to movementX/movementY based on region size
  - Sub-pixel regions (<1px): 3% speed
  - Tiny regions (1-5px): 10% speed
  - Small regions (5-15px): 25% speed
  - Larger regions: 100% speed
- Remove precision mode state (not needed)
- Remove cooldown logic (not needed)
- Remove click capture handler (not needed)
- Update cursor style and mouse handlers to use pointerLocked

**Benefits:**
- Much simpler code (removed ~100 lines of complexity)
- No lag when changing direction (no interpolation)
- Pointer lock active entire session (can't drift off map)
- Movement multiplier clearer than dampening

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-19 18:06:34 -06:00
Thomas Hallock 3bf127f344 feat: add precision controls for tiny regions in Know Your World
Implement automatic cursor dampening, super zoom on hover, and quick-escape to make sub-pixel regions (Gibraltar 0.08px, Jersey 0.82px) clickable. Fix crosshair accuracy to match dampened cursor position, add excluded region visualization (gray pre-labeled), and increase unfound region contrast (0.3→0.7 opacity).

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-19 18:06:34 -06:00
Thomas Hallock 1e8846cdb1 feat: add adaptive zoom magnifier for Know Your World map
Add intelligent magnifying glass feature with smooth animations:

Magnifier Features:
- Appears when 7+ regions overlap in 50×50px box OR region <8px
- Adaptive zoom (8×-24×) based on region density and size
- Smooth zoom/opacity animations using react-spring
- Dynamic positioning to avoid covering cursor
- Visual indicator box on main map shows magnified area
- Crosshair shows exact cursor position in magnified view

Implementation Details:
- Uses react-spring for smooth zoom and fade transitions
- Position calculated per quadrant (opposite corner from cursor)
- Zoom formula: base 8× + density factor + size factor
- Animated SVG viewBox for seamless zooming
- Dashed blue indicator rectangle tracks magnified region

UI/UX Improvements:
- Remove duplicate turn indicator (use player avatar dock)
- Hide arrow labels feature behind flag (disabled by default)
- Add Storybook stories for map renderer with tuning controls

This makes clicking tiny island nations and crowded regions much easier!

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 20:04:52 -06:00
Thomas Hallock 7bb03b8409 feat: add continent filtering to Know Your World game
Add continent-based filtering for the world map to make the game more playable by reducing visual clutter:

Continent Selection:
- Add continent selector to setup screen (only for world map)
- 7 continents + "All" option: Africa, Asia, Europe, North America, South America, Oceania, Antarctica
- Each continent button shows emoji and name

Map Filtering:
- Filter world map regions by selected continent using ISO 3166-1 country codes
- Calculate bounding box for filtered regions
- Automatically crop and scale viewBox to show only selected continent
- Add 10% padding around continent bounding box for better visibility

Technical Implementation:
- Create continents.ts with comprehensive country-to-continent mappings (256 countries)
- Add getFilteredMapData() function to filter regions and adjust viewBox
- Add calculateBoundingBox() to compute min/max coordinates from SVG paths
- Add selectedContinent field to game state and config (persisted to database)
- Add SET_CONTINENT move type and validator
- Update all map rendering components (StudyPhase, PlayingPhase, MapRenderer)

Benefits:
- Solves "too many small countries" problem on world map
- Allows focused study of specific geographic regions
- Dynamic viewBox adjustment provides optimal zoom level
- Maintains full world map option for comprehensive play

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 20:04:52 -06:00
Thomas Hallock 25e24a7cbc feat: add Know Your World geography quiz game
Add new arcade game for testing geography knowledge:

Game Features:
- 4 phases: Setup, Study, Playing, Results
- 3 multiplayer modes: Cooperative, Race, Turn-Based
- 2 maps: World countries, USA states
- Configurable study mode (0, 30, 60, or 120 seconds)
- Return to Setup and New Game options in game menu
- Small region labels with arrows for improved visibility

Map Rendering:
- 8-color deterministic palette with hash-based assignment
- Opacity-based states (20-27% unfound, 100% found)
- Enhanced label visibility with text shadows
- Smart bounding box calculation for small regions
- Supports both easy (outlines always visible) and hard (outlines on hover/found) difficulty

Game Modes:
- Cooperative: All players work together to find all regions
- Race: First to click gets the point
- Turn-Based: Players take turns finding regions

Study Phase:
- Optional timed study period before quiz starts
- Shows all region labels for memorization
- Countdown timer with skip option

Dependencies:
- Add @svg-maps/world and @svg-maps/usa packages

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 20:04:52 -06:00