Adds real-time document detection to the camera capture on session
summary pages. Uses OpenCV.js for edge detection and perspective
correction.
Key features:
- Multi-quad tracking: detects ALL quadrilaterals, not just largest
- Scores quads by stability over time (filters transient detections)
- Visual feedback: yellow (detecting) → green (stable) → bright green (locked)
- Auto-crops and deskews captured documents
- Falls back to raw photo if no document detected
Technical details:
- OpenCV.js (~8MB) lazy-loaded only when camera opens
- Tracks quads across frames by matching corner positions
- Filters by area (15-95% of frame) and document aspect ratios
- Locks on after 5 frames with 50%+ stability
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Major changes:
1. Sentinel approach for skill recency refresh
- Added 'recency-refresh' session status and SlotResult source field
- BKT skips pKnown updates for sentinel records (zero-weight)
- refreshSkillRecency() now inserts sentinel records instead of updating DB field
- Single source of truth: all lastPracticedAt comes from problem history
2. Skill progress chart (new component)
- 100% stacked area chart showing skill distribution over time
- Clickable legend cards for filtering by classification
- Adaptive time window presets (Recent, Last N, All)
- Synthetic "current" snapshot ensures chart matches legend staleness
3. Trend-aware encouragement messages
- Linear regression to detect improving/declining/stable trends
- Session timing analysis (gap detection, frequency patterns)
- Window-aware scope text ("over the past 2 weeks", "since Nov 15")
- Priority-based message selection (urgent issues first)
- Consistent "stale" terminology (not "rusty")
4. Dashboard improvements
- Virtualized session history list for performance
- Paginated session history API with cursor-based pagination
- BKT-computed lastPracticedAt used throughout (single source of truth)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace fixed-position ProjectingBanner with FLIP-based BannerSlots:
- Banners now render in document flow (relative positioning)
- Content flows naturally around banners
- FLIP animation only uses fixed positioning during ~400ms transition
- After animation, banner returns to document flow at target slot
Architecture:
- ContentBannerSlot/NavBannerSlot: Render content in-flow when active
- ProjectingBanner: Orchestrates FLIP animation during slot transitions
- Uses framer-motion springs for smooth position/size interpolation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit includes accumulated work from the SessionMode system:
- Add SkillUnlockBanner component for celebrating skill mastery
- Improve SessionSummary to show skill unlock celebrations
- Add session detail page at /practice/[studentId]/session/[sessionId]
- Update seedTestStudents script with more realistic test data
- Extend skill-tutorial-config with more skill mappings
- Improve BKT compute with better uncertainty handling
- Update progress-manager with skill completion tracking
- Remove legacy sessions API routes (replaced by session-plans)
- Add migration 0037 for practice_sessions schema cleanup
- Add plan documents for celebration wind-down and SessionMode
- Update gitignore to exclude db backups
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Student Notes Feature:
- Add notes column to players table with migration
- Create NotesModal component with zoom animation from student tile
- Add notes button on each student card in StudentSelector
- Support viewing and editing notes directly in modal
- Fix modal reopening bug with pointerEvents during animation
- Fix spring animation to start from clicked tile position
BKT & Curriculum Improvements:
- Add configurable BKT thresholds via admin settings
- Add skill anomaly detection API endpoint
- Add next-skill recommendation API endpoint
- Add problem history API endpoint
- Improve skills page with BKT classifications display
- Add skill tutorial integration infrastructure
Dashboard & Session Improvements:
- Enhanced dashboard with notes tab
- Improved session summary display
- Add StartPracticeModal stories
Test Infrastructure:
- Add seedTestStudents.ts script for BKT manual testing
- Add generateTrajectoryData.ts for simulation data
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add smooth spring-animated accordion expand/collapse using react-spring
- Add dynamic scroll indicators that show when content is scrolled
- Auto-scroll to show expanded category content optimally
- Replace ambiguous arrows with "Show/Hide" + rotating chevron
- Make modal full-screen on mobile, centered on desktop
- Add sticky category headers within scroll container
- Fix z-index layering using shared constants
- Add optimistic updates for skill mutations (instant UI feedback)
- Fix React Query cache sync for live skill updates
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove dead code from abandoned 3D printing initiative:
- Delete jobManager.ts (had unbounded memory growth)
- Delete openscad.worker.ts (unused)
- Delete 3D model files from public/
- Remove openscad-wasm-prebuilt dependency
- Clean up doc references
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add SimpleLetterKeyboard component for touch devices (react-simple-keyboard)
- Skip spaces when counting letters for name confirmation
(e.g., "US Virgin Islands" → type U, S, V)
- Hide MyAbacus floating button when virtual keyboard is shown
- Add Storybook stories for testing letter confirmation flow
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replace point sampling with proper computational geometry using @flatten-js/core.
Previous approach (strategic points):
- Tested 9 hardcoded points (corners + center + edge midpoints)
- Still sampling-based, just smarter sampling
- Could miss edge cases with complex shapes
New approach (flatten-js):
- Convert SVG path to Polygon using getPointAtLength() (50 samples)
- Convert detection box to Box in SVG coordinates
- Use polygon.intersect(box) for precise intersection test
- Also checks boxContainsRegion for tiny regions fully inside box
- Proper computational geometry, not heuristics
Algorithm:
1. Sample 50 points evenly along SVG path using getTotalLength()
2. Create Polygon from sampled points
3. Transform detection box corners to SVG coordinates
4. Create Box from transformed corners
5. Check: polygon.intersect(box) || box.contains(polygon.box)
Benefits:
- Mathematically correct intersection detection
- No guessing about where to sample
- Handles all cases: intersecting, contained, disjoint
- Fallback to 9-point sampling if flatten-js fails
Dependencies:
- Added @flatten-js/core for 2D computational geometry
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Problem:
- JavaScript's 64-bit floats lose precision with ultra-small movements
- Vatican City (~0.05px) requires 0.03x dampened cursor (0.001px precision)
- At 1000x zoom with tiny deltas, floating-point rounding causes "one pixel works"
- Coordinate transformations compound precision loss
Solution:
- Install big.js for arbitrary-precision decimal arithmetic
- Use Big for cursor position tracking (cursorPositionRef stores Big values)
- Use Big for movement delta calculations (e.movementX * 0.03)
- Use Big for container → SVG coordinate transformations
- Use Big for zoom viewport calculations at extreme zoom levels (1000x)
- Convert to numbers only when interfacing with DOM/display
Technical details:
- cursorPositionRef: { x: Big; y: Big } instead of { x: number; y: number }
- Cursor deltas: new Big(e.movementX).times(currentMultiplier)
- SVG coordinates: cursorXBig.minus(offset).times(scale).plus(viewBoxX)
- Zoom viewport: new Big(viewBoxWidth).div(testZoom)
- Maintains full precision through entire calculation chain
This should allow Vatican City to be clickable from multiple cursor positions
instead of requiring exact pixel-perfect positioning.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
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>
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>
Add complete sharing system for worksheet configurations:
Database Schema:
- New worksheet_shares table with short share IDs (7-char base62)
- Stores worksheetType, config JSON, views, creator IP hash, optional title
- Migration 0021 creates the table
Share ID Generation:
- Cryptographically secure base62 IDs (3.5 trillion combinations)
- Collision detection with retry logic (max 5 attempts)
- Validation function for ID format checking
API Endpoints:
- POST /api/worksheets/share - Creates share, returns URL
- GET /api/worksheets/share/[id] - Retrieves config, increments views
- Uses serializeAdditionConfig() for consistent config formatting
Share Modal:
- Auto-generates share link on open (no button needed)
- Displays QR code for mobile sharing (theme-aware colors)
- Copy to clipboard functionality with visual feedback
- Loading states during generation
Dependencies:
- Added qrcode + @types/qrcode for QR code generation
Config Serialization:
- Share uses same serializeAdditionConfig() as database auto-save
- Ensures version field and structure consistency
- Shared configs match database-saved settings exactly
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Remove ngrok tunnel integration - requires account signup.
User will test camera locally with incognito mode instead.
Also removed LAN IP detection feature:
- Reverted QRCodeDisplay to use window.location.origin directly
- Deleted /api/network/lan-ip endpoint
- Simplified dev script back to original
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Run ngrok automatically alongside the dev server to enable HTTPS
access for testing camera features on phones.
Changes:
- Install ngrok and concurrently packages
- Update dev script to run ngrok tunnel on port 3000
- Add dev:no-tunnel fallback script (no HTTPS tunnel)
Usage:
pnpm run dev # Dev server + ngrok HTTPS tunnel
pnpm run dev:no-tunnel # Dev server only (HTTP)
When running with tunnel:
- ngrok will display HTTPS URL in console
- Use that URL for testing camera on phones
- Camera access works over HTTPS (ngrok URL)
- LAN IP detection still works for localhost testing
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- dateFormatting.ts: getDefaultDate() for consistent date formatting
- layoutCalculations.ts: getDefaultColsForProblemsPerPage() and calculateDerivedState()
- Pure functions, easy to test
- Removes 32 lines from main component
Add gray-matter, remark, remark-gfm, and remark-html dependencies
that were missing from the blog feature commits, causing webpack
"Module not found" errors in CI/CD.
These packages are required by src/lib/blog.ts for markdown processing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Migrate 3D abacus preview generation from server-side OpenSCAD to client-side
WASM execution using web workers.
Changes:
- Add openscad-wasm-prebuilt dependency for browser-based rendering
- Refactor STLPreview to use web worker for non-blocking WASM execution
- Create openscad.worker.ts for isolated 3D model generation
- Add abacus-inline.scad template for parametric abacus generation
- Improve preview debouncing (500ms) and error handling
Benefits:
- No server-side OpenSCAD dependency required
- Faster preview updates (no network roundtrip)
- Better UX with non-blocking worker execution
- Consistent rendering across environments
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The calendar generation scripts were in scripts/ directory which wasn't
included in tsconfig.server.json, so they weren't being compiled during
build. This required tsx in production just to import .tsx files at runtime.
Changes:
- Moved generateCalendarComposite.tsx and generateCalendarAbacus.tsx to src/utils/calendar/
- Removed CLI interface code from these files (they're now pure utility modules)
- Updated imports in API routes to use @/utils/calendar/...
- Moved tsx back to devDependencies where it belongs
- Removed scripts/ copy from Dockerfile (no longer needed)
Now these files are compiled to JavaScript during the build process and
don't require tsx at runtime. This fixes the architecture issue properly.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Calendar generation scripts need tsx at runtime to execute TypeScript files,
but tsx was in devDependencies which are not installed in production builds.
This caused calendar preview and PDF generation to fail in production with:
"EACCES: permission denied, mkdir '/nonexistent'" when trying to run npx tsx
Moving tsx to dependencies ensures it's available in production for:
- apps/web/scripts/generateCalendarComposite.tsx
- apps/web/scripts/generateCalendarAbacus.tsx
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add embla-carousel-autoplay dependency to enable smooth automatic
rotation of games in the hero carousel.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add embla-carousel-react dependency to enable smooth carousel
functionality for displaying player profiles on the games page.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Installed @types/react-textfit to resolve TypeScript compilation error
in PlayingGuideModal.tsx. This package provides type definitions for
the react-textfit library used in the Rithmomachia guide component.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replace ellipsized tab labels with react-textfit library:
- Install react-textfit package
- Use Textfit component for tab text labels
- Auto-scales font size (8px-14px) using binary search to fit width
- No more ellipsis (...) on narrow tabs
- Full tab labels always visible and readable
- Icon stays fixed size, only text scales
Tab labels now automatically shrink to fit available space while
remaining fully readable.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implement ability to dock the Rithmomachia playing guide to left or right
side of the board screen. When docked, guide and board are in separate
panels with a resizable divider between them.
Features:
- Drag guide to left/right edge (within 100px) to dock it
- Resizable divider using react-resizable-panels library
- Guide defaults to 35% width, resizable between 20-50%
- Board takes remaining space (minimum 50%)
- Undock button (⛶) returns guide to floating modal mode
- No overlap between board and guide when docked
- Dragging disabled when docked
- Styling adjusted for docked mode (no shadows, no border-radius)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added i18next and react-i18next to package.json to fix Docker build failure.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add yjs-demo arcade game with collaborative state management
- Add Yjs persistence layer for real-time sync
- Update socket server with Yjs support
- Update Rithmomachia game component
- Add yjs type definitions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add smooth physics-based animations for card and arrow movements:
- Add @react-spring/web dependency
- Create AnimatedCard component with spring animations
- Create AnimatedArrow component with spring animations
- Add viewport resize handling with debounced isResizing flag
- Conditionally disable animations during drag and resize (immediate mode)
- Enable spring animations only for socket position updates
- Add throttled position syncing (100ms) during drag operations
- Convert all positioning to viewport percentages (0-100)
- Track viewport dimensions and reposition cards on resize
Cards and arrows now smoothly animate when positions update from other
connected windows, while maintaining instant feedback during local
drag operations and viewport resizes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add a QR code sharing option alongside existing copy buttons.
When clicked, opens a popover with:
- QR code encoding the room's share URL
- "Scan to Join" heading
- Clickable copy button for the URL
Uses qrcode.react library with Radix UI popover component.
Button styled with orange gradient to differentiate from existing
blue link and purple code copy buttons.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add a fun, interactive flashcard display to the homepage's flashcard
generator section. Users can drag and throw 8-15 randomly generated
flashcards around with realistic physics-based momentum.
Features:
- Drag and drop flashcards with mouse/touch
- Throw cards with velocity-based physics
- 8-15 randomly generated flashcards (100-999 range)
- Real AbacusReact components for each card
- Client-side rendering to avoid hydration errors
Technical implementation:
- Uses @use-gesture/react for drag gesture handling
- Uses @react-spring/web for smooth physics animations
- Cards generated client-side with useEffect to prevent SSR mismatch
- Each card maintains its own spring-based position and rotation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
BREAKING CHANGE: Database schemas now accept any string for game names
This implements Critical Fix#1 from AUDIT_2_ARCHITECTURE_QUALITY.md
Changes:
- Remove hardcoded enums from all database schemas
- arcade-rooms.ts: gameName now accepts any string
- arcade-sessions.ts: currentGame now accepts any string
- room-game-configs.ts: gameName now accepts any string
Runtime Validation:
- Add isValidGameName() helper to validate against registry
- Add assertValidGameName() helper for fail-fast validation
- Update settings API to use runtime validation instead of hardcoded array
Benefits:
✅ No schema migration needed when adding new games
✅ No TypeScript compilation errors for new games
✅ Single source of truth: validator registry
✅ "Just register and go" - no database changes required
Migration Impact:
- Existing data is compatible (strings remain strings)
- No data migration needed
- TypeScript will now allow any string, but runtime validation enforces correctness
This eliminates the most critical architectural issue identified in the audit.
Future games can be added by:
1. Register validator in validators.ts
2. Register game in game-registry.ts
That's it! No database schema changes needed.
Create foundation for modular arcade game architecture:
**Game SDK** (`/src/lib/arcade/game-sdk/`):
- Stable API surface that games can safely import
- Type-safe game definition with `defineGame()` helper
- Controlled hook exports (useArcadeSession, useRoomData, etc.)
- Player ownership and metadata utilities
- Error boundary component for game crashes
**Manifest System**:
- YAML-based game manifests with Zod validation
- Game metadata (name, icon, description, difficulty, etc.)
- Type-safe manifest loading with `loadManifest()`
**Game Registry**:
- Central registry for all arcade games
- Explicit registration pattern via `registerGame()`
- Helper functions to query available games
**Type Safety**:
- Full TypeScript contracts for games
- GameValidator, GameState, GameMove, GameConfig types
- Compile-time validation of game implementations
This establishes the plugin system for drop-in arcade games.
Next: Create demo games to exercise the system.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add comprehensive access control system for arcade rooms with 6 modes:
- open: Anyone can join (default)
- locked: Only current members allowed
- retired: Room no longer functions
- password: Requires password to join
- restricted: Only users with pending invitations can join
- approval-only: Requires host approval via join request system
Database Changes:
- Add accessMode field to arcade_rooms (replaces isLocked boolean with enum)
- Add password field to arcade_rooms (hashed with bcrypt)
- Create room_join_requests table for approval-only mode
New API Endpoints:
- PATCH /api/arcade/rooms/:roomId/settings - Update room access mode and password (host only)
- POST /api/arcade/rooms/:roomId/transfer-ownership - Transfer ownership to another member (host only)
- POST /api/arcade/rooms/:roomId/join-request - Request to join approval-only room
- GET /api/arcade/rooms/:roomId/join-requests - Get pending join requests (host only)
- POST /api/arcade/rooms/:roomId/join-requests/:requestId/approve - Approve join request (host only)
- POST /api/arcade/rooms/:roomId/join-requests/:requestId/deny - Deny join request (host only)
Updated Endpoints:
- POST /api/arcade/rooms/:roomId/join - Now validates access modes before allowing join:
* locked: Rejects all joins
* retired: Rejects all joins (410 Gone)
* password: Requires password validation
* restricted: Requires valid pending invitation
* approval-only: Requires approved join request
* open: Allows anyone (existing behavior)
Libraries:
- Add room-join-requests.ts for managing join request lifecycle
- Ownership transfer updates room.createdBy and member.isCreator flags
- Socket.io events for join request notifications and ownership transfers
Migration: 0007_access_modes.sql
Next Steps (UI not included in this commit):
- RoomSettingsModal for configuring access mode and password
- Join request approval UI in ModerationPanel
- Ownership transfer UI in ModerationPanel
- Password input in join flow
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add tsconfig.server.json to compile server-side TypeScript
- Install tsc-alias to resolve path aliases (@/*) in compiled JS
- Update build script to run tsc + tsc-alias before Next.js build
- Update dev script to compile server files before starting
- Remove tsx runtime dependencies from server.js
- Add compiled JS files for socket-server, db, and arcade modules
This enables production builds to run with pure Node.js without
requiring tsx or ts-node at runtime, as required for Docker deployment.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add comprehensive documentation and tooling to enforce code quality
checks before every commit. This regime persists across all Claude
Code sessions via `.claude/` directory files.
**The Regime** (mandatory before every commit):
1. TypeScript type checking (0 errors)
2. Biome formatting (auto-applied)
3. Linting with auto-fix (0 errors, 0 warnings)
4. Final verification
**Implementation:**
- `.claude/CLAUDE.md`: Quick reference for Claude Code sessions
- `.claude/CODE_QUALITY_REGIME.md`: Detailed regime documentation
- `npm run pre-commit`: Single command to run all checks
**Why no pre-commit hooks:**
Avoided for religious reasons. Claude Code is responsible for
enforcing quality checks through session-persistent documentation.
**Usage:**
```bash
# Before every commit
npm run pre-commit
# Or run steps individually
npm run type-check
npm run format
npm run lint:fix
npm run lint
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add Biome for formatting and general linting, with minimal ESLint
configuration for React Hooks rules only. This provides:
- Fast formatting via Biome (10-100x faster than Prettier)
- General JS/TS linting via Biome
- React Hooks validation via ESLint (rules-of-hooks)
- Import organization via Biome
Configuration files:
- biome.jsonc: Biome config with custom rule overrides
- eslint.config.js: Minimal flat config for React Hooks only
- .gitignore: Added Biome cache exclusion
- LINTING.md: Documentation for the setup
Scripts added to package.json:
- npm run lint: Check all files
- npm run lint:fix: Auto-fix issues
- npm run format: Format all files
- npm run check: Full Biome check
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Remove @myriaddreamin/typst-* packages that are no longer needed.
This eliminates Docker overlay conflicts with hoisted node_modules.
Removed packages (-365):
- @myriaddreamin/typst-all-in-one.ts
- @myriaddreamin/typst-ts-renderer
- @myriaddreamin/typst-ts-web-compiler
- @myriaddreamin/typst.ts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Changed CreateSessionOptions.activePlayers from number[] to string[]
- Updated socket-server.ts fallback from [1] to [data.userId]
- Added debug logging to validateFlipCard to diagnose turn validation issues
This ensures that when a session is created without explicit activePlayers,
it uses the actual UUID of the requesting player instead of the numeric value 1.
- Install @tanstack/react-query
- Create QueryClientProvider in ClientProviders with stable client instance
- Add queryClient.ts with createQueryClient() and api() helper
- Add api() helper that wraps fetch with automatic /api prefix
- Add example.ts with complete CRUD hook examples
- Configure sensible defaults (5min staleTime, retry once)
All API routes are now prefixed with /api automatically via api() helper.
Add script to capture deployment metadata (git commit, branch, timestamp, version) at build time and integrate it into the build process.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fix duplicate color properties in single player mode styling
- Fix className prop passing to css() function in both single and multiplayer modes
- Replace undefined 'super-bounce' animation with 'gentle-bounce'
The make-plural pluralization integration is working correctly with proper
display of "1 pair" vs "2 pairs", "1 move" vs "3 moves", etc.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>