Commit Graph

1269 Commits

Author SHA1 Message Date
Thomas Hallock
98cd019d4a fix: add xmlns to AbacusStatic for Typst SVG parsing
- Add xmlns="http://www.w3.org/2000/svg" to AbacusStatic root svg element
- Fixes "failed to parse SVG (missing root node)" Typst error
- React's renderToStaticMarkup doesn't add xmlns by default
- Required for standalone SVG files used outside HTML context
- Added debug logging to calendar generation route

Root cause: Typst's SVG parser requires explicit XML namespace declaration.
React assumes SVGs are embedded in HTML where xmlns is optional.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 20:10:22 -06:00
Thomas Hallock
08c6a419e2 fix(web): use AbacusStatic for calendar SVG generation
- Switch from AbacusReact to AbacusStatic in generateCalendarAbacus.tsx
- Fixes "failed to parse SVG (missing root node)" Typst error
- AbacusReact can't be rendered server-side with renderToStaticMarkup
- AbacusStatic is designed for pure server-side rendering

Root cause: AbacusReact has "use client" directive and uses hooks,
which causes renderToStaticMarkup to generate invalid/empty SVG.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 19:25:18 -06:00
Thomas Hallock
329e623212 fix(web): add dynamic export to rithmomachia page
Attempt to fix "Cannot access 'Z' before initialization" error during
static generation by forcing dynamic rendering.

Note: This doesn't fully resolve the initialization issue, but prevents
build from attempting static generation which causes the error.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 18:51:46 -06:00
Thomas Hallock
8439727b15 feat(web): improve calendar abacus preview styling
CalendarPreview changes:
- Remove showNumbers display from all abaci for cleaner calendar look
- Increase day abaci scaleFactor from 0.35 to 1.0 (fills grid squares)
- Remove year from month title (shows only month name)

CalendarConfigPanel changes:
- Replace link to /create with inline AbacusDisplayDropdown
- Add preview abacus showing current style (value=12, 2 columns)
- Users can now edit abacus styles directly in calendar page

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 18:51:46 -06:00
Thomas Hallock
7ce1287525 fix(web): fix Typst PDF generation path resolution
- Change SVG image paths from absolute to relative in typstGenerator
- Execute typst compilation from tempDir with cwd option
- Fixes "file not found" error caused by Typst doubling absolute paths

Root cause: Typst treats absolute paths as relative and prepends working
directory, resulting in incorrect paths like:
/tmp/calendar-123/tmp/calendar-123/year.svg

Solution: Use relative paths ("year.svg") and run from tempDir.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 18:51:46 -06:00
Thomas Hallock
903dea2584 feat(web): add test page for AbacusStatic RSC compatibility
- Create /test-static-abacus page demonstrating pure Server Component usage
- Uses @soroban/abacus-react/static import (no client code)
- Renders 12 abacus displays with zero client-side JavaScript
- Verifies RSC export path works correctly in Next.js build

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 18:51:46 -06:00
Thomas Hallock
3588d5acde feat(web): add test page for AbacusStatic Server Component
Creates /test-static-abacus route to demonstrate and verify that
AbacusStatic works correctly in React Server Components.

The page:
- Has NO "use client" directive (pure Server Component)
- Renders 12 different abacus values as static preview cards
- Uses compact mode and hideInactiveBeads for clean displays
- Includes visual confirmation that RSC rendering works

This serves as both a test and reference implementation for
using AbacusStatic in Next.js App Router Server Components.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 18:29:16 -06:00
Thomas Hallock
7228bbc2eb refactor(web): import utility functions from abacus-react
Re-export core utility functions from @soroban/abacus-react instead of
duplicating implementations:

- beadDiff.ts: Re-exports calculateBeadDiff, calculateBeadDiffFromValues,
  areStatesEqual, etc. Keeps app-specific calculateMultiStepBeadDiffs
  and validateBeadDiff.

- abacusInstructionGenerator.ts: Re-exports numberToAbacusState,
  calculateBeadChanges, and related types. Keeps app-specific
  tutorial generation logic.

- TutorialPlayer.tsx: Import calculateBeadDiffFromValues from abacus-react

- TutorialEditor.tsx: Import calculateBeadDiffFromValues from abacus-react

Eliminates ~200 lines of duplicate utility function implementations.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 17:17:17 -06:00
Thomas Hallock
ff1d60a233 refactor(web): use compact prop for inline mini-abacus
Replace manual customStyles with compact={true} in AbacusTarget.tsx.

Before: 7 props + customStyles override
After: compact={true} automatically handles frame visibility

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 17:17:17 -06:00
Thomas Hallock
9f7f001d74 refactor(web): use ABACUS_THEMES instead of manual style definitions
Replace manual theme style definitions with ABACUS_THEMES presets:
- MyAbacus.tsx: Use ABACUS_THEMES.light and ABACUS_THEMES.trophy
- HeroAbacus.tsx: Use ABACUS_THEMES.light
- LevelSliderDisplay.tsx: Use ABACUS_THEMES.dark

Eliminates ~60 lines of duplicate theme style code.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 17:17:17 -06:00
Thomas Hallock
af0552ccd9 test: verify compose-updater automatic deployment cycle
Add test comment to trigger automatic deployment and verify that
compose-updater successfully updates the container without crashing
with the new separate project names configuration.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 17:04:05 -06:00
Thomas Hallock
2b06aae394 test: trigger compose-updater deployment test
Testing that compose-updater successfully updates without crashing itself
2025-11-03 16:32:13 -06:00
Thomas Hallock
28a2d40996 fix: remove distracting parallax and wobble 3D effects
Remove all parallax hover effects and wobble physics from 3D enhancement system
as they were distracting and worsened the user experience.

Changes:
- Remove Abacus3DPhysics interface completely
- Remove physics3d prop from AbacusConfig and component
- Remove calculateParallaxOffset utility function
- Remove mouse tracking infrastructure (containerRef, mousePos, handleMouseMove)
- Update enhanced3d type to only support 'subtle' | 'realistic' (removed 'delightful')
- Update all 3D utilities to remove delightful mode support
- Remove all Delightful stories from Storybook
- Update Interactive Playground to remove parallax controls
- Change MyAbacus from delightful to realistic mode

The 3D enhancement system now focuses purely on visual improvements
(materials, lighting, textures) without any motion-based effects.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 15:41:49 -06:00
Thomas Hallock
37e330f26e feat: enable 3D enhancement on hero/open MyAbacus modes
Added delightful 3D mode to the hero and open states of MyAbacus:
- Glossy heaven beads + satin earth beads for premium feel
- Dramatic lighting for impact
- Wood grain texture on golden frame
- Hover parallax enabled for interactive depth
- Only applies to hero/open modes (not button mode)

The giant hero abacus on the home page now has satisfying
material rendering and interactive parallax effects.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 15:41:49 -06:00
Thomas Hallock
5d97673406 fix: remove wobble physics and enhance wood grain visibility
**Changes:**
- Removed wobble physics feature (was janky and distracting)
- Increased wood grain opacity from 0.15 → 0.4 (realistic) and 0.45 (delightful)
- Enhanced wood grain pattern with bolder strokes and more visible knots
- Removed getWobbleRotation utility function
- Simplified Abacus3DPhysics interface to only hoverParallax
- Updated all stories to remove wobble references
- Removed velocity tracking code from Bead component

Wood grain is now much more visible on frame elements without
affecting bead spacing or layout.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 15:41:49 -06:00
Thomas Hallock
096104b094 fix: use absolute positioning for hero abacus to eliminate scroll lag
Replace laggy JavaScript scroll tracking with proper CSS positioning:

Before:
- Used position: fixed with JavaScript scroll listener
- Calculated top position dynamically: calc(60vh - ${scrollY}px)
- Caused noticeable lag on mobile and slower browsers

After:
- Hero mode: position: absolute (scrolls naturally with document)
- Button mode: position: fixed (stays in viewport at bottom-right)
- Open mode: position: fixed (stays in viewport at center)
- Zero JavaScript scroll tracking needed

Result: Buttery smooth scrolling on all devices with zero lag.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 15:41:49 -06:00
Thomas Hallock
f03d341314 fix: adjust hero abacus position to avoid covering subtitle
Move hero abacus down from 50vh to 60vh to prevent it from overlapping
the subtitle text ("master the ancient art..." etc.) on the home page.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 13:24:15 -06:00
Thomas Hallock
ed9a050d64 fix: resolve z-index layering and hero abacus visibility issues
Fix two critical issues with the trophy abacus system:

1. Hero abacus appearing on all pages:
   - Root cause: HomeHeroProvider now wraps all pages globally
   - Solution: Use pathname check to detect actual home page routes
   - Only show hero mode on: /, /en, /de, /ja, /hi, /es, /la

2. Z-index conflicts causing layering issues:
   - AppNavBar had hardcoded z-index: 1000 (DROPDOWN layer)
   - Should use Z_INDEX.NAV_BAR (100) for proper layering
   - Tooltip had z-index: 50, should use Z_INDEX.TOOLTIP (1000)

This ensures:
- Hero abacus only appears on home page, not all pages
- Trophy abacus (z-index 30001) appears above ALL content
- Nav bar and tooltips use correct z-index constants
- No stacking context conflicts

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 13:24:15 -06:00
Thomas Hallock
423274657c fix: correct hero abacus scroll direction to flow with page content
The hero abacus was scrolling in the opposite direction of page content due to incorrect math. Fixed by subtracting scroll position instead of adding it.

Change: top: calc(50vh - ${scrollY}px) instead of calc(50vh + ${scrollY}px)

Now the abacus properly scrolls up with the page content when scrolling down.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 13:24:15 -06:00
Thomas Hallock
6620418a70 feat: add unified trophy abacus with hero mode integration
Implement a single abacus component that seamlessly transitions between three states: hero mode on the home page, compact button in the corner, and full-screen modal display.

Key features:
- Hero mode: Large white abacus at top-center of home page, interactive with beads
- Button mode: Golden mini abacus in bottom-right corner when hero scrolled away or on other pages
- Open mode: Full-screen golden abacus with blur backdrop, accessible from button
- Smooth fly-to-corner animation when scrolling past hero section
- Two-way sync between hero and trophy abacus values via HomeHeroContext
- Highest z-index layer (30000+) to appear above all content

Implementation:
- Create MyAbacus component handling all three states with smooth transitions
- Add MyAbacusContext for global open/close state management
- Move HomeHeroProvider to ClientProviders for global access
- Replace HeroAbacus with HeroSection placeholder on home page
- Fix flashcard z-index by creating proper stacking context (z-index: 1)
- Add MY_ABACUS z-index constants (30000-30001)
- Add calendar page components with correct styled-system imports

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 13:24:15 -06:00
Thomas Hallock
88993f3662 fix: tolerate OpenSCAD CGAL warnings if output file is created
OpenSCAD 2021.01 (Debian stable) has CGAL geometry bugs that cause
non-zero exit status when processing complex STL operations, but it
still produces valid output files.

Instead of failing the job when OpenSCAD exits with non-zero status,
we now check if the output file was created. If it exists, we proceed
with the job. Only if the file is missing do we treat it as a failure.

This allows 3D model generation to work on production despite the
older OpenSCAD version's CGAL warnings.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 12:18:00 -06:00
Thomas Hallock
d7b35d9544 fix: mark dynamic routes as force-dynamic to prevent static generation errors
Next.js build was failing because routes using headers() were being
statically generated during build time. Added `export const dynamic = 'force-dynamic'`
to:
- /api/player-stats (uses getViewerId which reads headers)
- /api/debug/active-players (uses getViewerId which reads headers)
- /opengraph-image (reads filesystem during render)

Build errors:
- Route /api/player-stats couldn't be rendered statically because it used `headers`
- Route /api/debug/active-players couldn't be rendered statically because it used `headers`
- Error occurred prerendering page "/opengraph-image"

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 11:09:06 -06:00
Thomas Hallock
b67cf610c5 fix: various game improvements and UI enhancements
Collection of improvements across multiple games and components:

- Complement Race: Improve sound effects timing and reliability
- Card Sorting: Enhance drag-and-drop physics and visual feedback
- Memory Quiz: Fix input phase keyboard navigation
- Rithmomachia: Update playing guide modal content and layout
- PageWithNav: Add viewport context integration
- ArcadeSession: Improve session state management and cleanup
- Global CSS: Add utility classes for 3D transforms

Documentation:
- Add Google Classroom setup guide
- Update Claude Code settings

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 10:53:54 -06:00
Thomas Hallock
25880cc7e4 feat: add game preview system with mock arcade environment
Add comprehensive preview system for arcade games:

- GamePreview component: Renders any arcade game in preview mode
- MockArcadeEnvironment: Provides isolated context for previews
- MockArcadeHooks: Mock implementations of useArcadeSession, etc.
- MockGameStates: Pre-defined game states for each arcade game
- ViewportContext: Track and respond to viewport size changes

Enables rendering game components outside of arcade rooms for:
- Documentation and guides
- Marketing/showcase pages
- Testing and development
- Game selection interfaces

Mock states include setup, playing, and results phases for all
five arcade games (matching, complement-race, memory-quiz,
card-sorting, rithmomachia).

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 10:53:54 -06:00
Thomas Hallock
b91b23d95f refactor: restructure /create page into hub with sub-pages
Reorganize create functionality into a central hub page:

- Move flashcard creation to /create/flashcards
- Add new creation hub at /create with options for:
  - Flashcards (existing feature)
  - Abacus 3D models (new feature)
  - Future creation tools

The hub page provides a clean navigation interface for all
content creation features.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 10:53:54 -06:00
Thomas Hallock
dafdfdd233 feat: add 3D printing support for abacus models
Add comprehensive 3D printing capabilities for generating custom
abacus models in STL format:

- OpenSCAD integration in Docker container
- API endpoint: POST /api/abacus/generate-stl
- Background job processing with status monitoring
- STL file preview with Three.js
- Interactive abacus customization page at /create/abacus
- Configurable parameters: columns, bead shapes, dimensions, colors
- Export formats: STL (for 3D printing), SCAD (for editing)

Components:
- STLPreview: Real-time 3D model viewer
- JobMonitor: Background job status tracking
- AbacusCustomizer: Interactive configuration UI

Docker: Add OpenSCAD and necessary 3D printing tools
Dependencies: Add three, @react-three/fiber, @react-three/drei

Generated models stored in public/3d-models/
Documentation: 3D_PRINTING_DOCKER.md

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 10:53:54 -06:00
Thomas Hallock
613301cd13 feat: add per-player stats tracking system
Implement comprehensive per-player statistics tracking across arcade games:

- Database schema: player_stats table with per-player metrics
- Migration: 0013_add_player_stats.sql for schema deployment
- Type system: Universal GameResult types supporting all game modes
  (competitive, cooperative, solo, head-to-head)
- API endpoints:
  - POST /api/player-stats/record-game - Record game results
  - GET /api/player-stats - Fetch all user's players' stats
  - GET /api/player-stats/[playerId] - Fetch specific player stats
- React hooks:
  - useRecordGameResult() - Mutation hook with cache invalidation
  - usePlayerStats() - Query hooks for fetching stats
- Game integration: Matching game now records stats on completion
- UI updates: /games page displays per-player stats in player cards

Stats tracked: games played, wins, losses, best time, accuracy,
per-game breakdowns (JSON), favorite game type, last played date.

Supports cooperative games via metadata.isTeamVictory flag where
all players share win/loss outcome.

Documentation added:
- GAME_STATS_COMPARISON.md - Cross-game analysis
- PER_PLAYER_STATS_ARCHITECTURE.md - System design
- MATCHING_GAME_STATS_INTEGRATION.md - Integration guide

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 10:53:54 -06:00
Thomas Hallock
9f51edfaa9 feat(games): add autoplay and improve carousel layout
Major improvements to the games hero carousel:
- Added smooth autoplay (4s delay, stops on interaction/hover)
- Made carousel full-width to reduce virtual scrolling artifacts
- Added horizontal padding for better buffer on edges
- Restructured layout: carousel is now full-width, rest of content
  remains constrained to max-width
- Removed containScroll setting to improve infinite loop behavior

The carousel now smoothly rotates through games automatically and
has better visual consistency at the loop edges.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 10:53:54 -06:00
Thomas Hallock
946e5d1910 feat: install embla-carousel-autoplay for games carousel
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>
2025-11-03 10:53:54 -06:00
Thomas Hallock
5a8c98fc10 fix(games): prevent horizontal page scroll from carousel overflow
Added overflowX: hidden to page container to clip carousel at viewport
level. This prevents the infinite carousel from making the entire page
horizontally scrollable while still allowing game cards to visually
extend beyond their container.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 10:53:54 -06:00
Thomas Hallock
876513c9cc refactor(games): remove wheel scrolling, enable overflow visible carousel
Removed non-functional wheel scrolling code and changed games carousel
to overflow: visible for a full-width effect that extends beyond the
container. Creates a more immersive, cinematic feel where game cards
bleed into the page edges.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 10:53:54 -06:00
Thomas Hallock
f80a73b35c fix(games): smooth scroll feel for carousel wheel navigation
Changed carousel wheel scrolling from discrete next/prev jumps to smooth
scrolling that follows the wheel delta. Now it feels like actually
scrolling instead of a rocket engine!

- Uses embla's internal scroll container directly
- Scales wheel delta by 0.5 for comfortable scroll speed
- Maintains horizontal scroll and shift+scroll detection

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 10:53:54 -06:00
Thomas Hallock
a224abb6f6 feat(games): add horizontal scroll support to carousels
Both games and player carousels now support horizontal scrolling with:
- Mouse wheel horizontal scroll (trackpad swipe gestures)
- Shift + vertical scroll for horizontal navigation
- Prevents page scroll when interacting with carousel

Implemented with custom wheel event handlers that detect horizontal
scroll intent and call embla's scrollNext/scrollPrev methods.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 10:53:54 -06:00
Thomas Hallock
187271e515 fix(games): use specific transition properties for smooth carousel loop
Fixed carousel looping issue by replacing generic 'transition: all' with
specific transition properties. Only transition opacity on carousel items
and transform/box-shadow/border-color on cards for hover effects.

This prevents CSS transitions from interfering with embla's carousel
transform animations at the loop wrap point.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 10:53:54 -06:00
Thomas Hallock
24231e6b2e feat(games): add rotating games hero carousel
Added a hero section at the top of the games page featuring a rotating
carousel of all available arcade games. Each card shows:
- Game icon and name
- Difficulty and player count
- Description
- Category chips (Multiplayer, Memory, Soroban, etc.)
- Game-specific gradient background

Uses embla-carousel for smooth dragging and navigation dots with game
icons for quick access. Cards link directly to each game's arcade page.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 10:53:54 -06:00
Thomas Hallock
ad5bb87325 refactor(games): remove redundant subtitle below nav
Removed the hero section subtitle since the page title is now in the
nav bar. The subtitle was awkwardly positioned where nobody would see it.
Added top padding to account for the fixed nav bar.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 10:53:54 -06:00
Thomas Hallock
d3fe6acbb0 fix(nav): show full navigation on /games page
Fixed AppNavBar auto-detecting /games route as needing minimal mode.
The /games page should use the full navigation bar (like /create and
/guide), not the minimal arcade nav with only a hamburger menu.

Changed route detection to only apply minimal nav to /arcade/* routes,
not /games route.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 10:53:53 -06:00
Thomas Hallock
96c760a3a5 chore: remove static icon.svg replaced by dynamic generation
The static icon.svg has been replaced by dynamic day-of-month favicon
generation via src/app/icon/route.tsx which calls scripts/generateDayIcon.tsx

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 08:59:14 -06:00
Thomas Hallock
944ad6574e feat: switch to royal color theme with transparent background
Update favicon design based on user preference:
- Ones place: Gold (#fbbf24, stroke #f59e0b)
- Tens place: Purple (#a855f7, stroke #7e22ce)
- Remove background circle for clean, transparent appearance

The royal color scheme provides better contrast and a more
sophisticated look while maintaining excellent legibility at small sizes.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 08:59:14 -06:00
Thomas Hallock
0e529be789 fix: reduce padding to minimize gap below last bead
Use asymmetric padding to crop tighter to the active bead region:
- Top: 8px (some breathing room above)
- Bottom: 2px (minimal gap below last bead)
- Sides: 5px

This eliminates the visible gap of column post structure below the
last active bead while maintaining clean spacing above.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 08:59:14 -06:00
Thomas Hallock
440b492e85 fix: use nested SVG viewBox for actual cropping, not just scaling
Previous approach used transforms to scale the entire SVG, which didn't
actually crop anything - just scaled everything uniformly.

New approach uses nested SVG with viewBox to truly crop the content:
- Outer SVG: 100x100 canvas with background circle
- Inner SVG: Uses viewBox to show only the cropped region
- viewBox dimensions vary per day based on active bead positions

Results:
- Day 1 (1 bead): viewBox height ~59px (narrow vertical crop)
- Day 15 (mixed): viewBox height ~88px (medium)
- Day 31 (many): viewBox height ~104px (tall vertical crop)
- Horizontal: Always ~110px (both columns with posts)

This actually maximizes bead size by showing only the relevant vertical region.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 08:59:14 -06:00
Thomas Hallock
83090df4df fix: separate horizontal and vertical bounding box logic
Clarify that horizontal and vertical cropping use different criteria:
- Horizontal (X): Always show full width of both columns (from structural rects)
- Vertical (Y): Crop dynamically to active bead positions + heights

This ensures consistent horizontal scale (0.8) across all days, with only
vertical positioning adjusting based on where active beads are located.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 08:59:14 -06:00
Thomas Hallock
0b2f48106a fix: include column posts in favicon bounding box
Refined the cropping algorithm to include structural elements (column posts)
in the bounding box calculation, not just active beads. This ensures the
complete abacus structure is visible.

Algorithm changes:
- X range: Full width from leftmost to rightmost post (all columns)
- Y range: From top active bead to bottom active bead (tight vertical crop)

Results:
- Consistent scale of 0.8 across all days (vs original 0.48)
- Shows complete column structure with posts
- Vertical position adjusts based on active bead positions
- Maintains visual context while maximizing bead visibility

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 08:59:14 -06:00
Thomas Hallock
567032296a feat: dynamically crop favicon to active beads for maximum size
Implement bounding box calculation to crop the favicon SVG to show only
the active beads, maximizing their size within the 100x100 icon canvas.

Algorithm:
1. Parse rendered SVG to find all active bead positions (via regex)
2. Calculate bounding box with 15px padding
3. Compute optimal scale to fit within 96x96 (leaving border room)
4. Apply transform: translate + scale + translate to crop and center

Results:
- Day 1-9 (few beads): scale ~1.14 (2.4x larger than before)
- Day 31 (many beads): scale ~0.74 (1.5x larger than before)
- Original fixed scale: 0.48

This uses no external dependencies - just regex parsing of the rendered
SVG to extract active bead coordinates.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 08:59:14 -06:00
Thomas Hallock
e1369fa275 fix: configure favicon metadata and improve bead visibility
Metadata fixes:
- Update icon path from /icon.svg to /icon to match route handler
- Ensure proper MIME type (image/svg+xml) is set in both metadata and response

Favicon visibility improvements:
- Increase AbacusReact scaleFactor from 1.0 to 1.8 for larger beads
- Add hideInactiveBeads prop to hide inactive beads
- Add hide-inactive-mode class to wrapper for CSS to take effect
- Adjust outer scale to 0.48 to fit larger abacus in 100x100 viewBox
- Reposition abacus with translate(28, -2) for proper centering

CSS cleanup:
- Strip !important declarations from generated SVG (production code policy)
- Apply same fix to OG image generator

User needs to restart dev server to clear in-memory cache.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 08:59:14 -06:00
Thomas Hallock
4d0795a9df feat: dynamic day-of-month favicon using subprocess pattern
- Create scripts/generateDayIcon.tsx for on-demand icon generation
- Route handler calls script via execSync (avoids Next.js react-dom/server restriction)
- Implement in-memory caching to minimize subprocess overhead
- Show current day (01-31) on 2-column abacus in US Central Time
- High-contrast design: blue/green beads, 2px strokes, gold border
- Document SSR pattern in .claude/CLAUDE.md for future reference

Fixes the Next.js limitation where route handlers cannot import react-dom/server
by using subprocess pattern - scripts CAN use react-dom/server, route handlers
call them via execSync and cache the results.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 08:59:14 -06:00
Thomas Hallock
712ee58e59 refactor(games): move page title to nav bar
Move 'Soroban Arcade' title from page content to navigation bar
for consistency with other app pages (create, guide).

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 08:59:14 -06:00
Thomas Hallock
6333c60352 feat(i18n): update games page hero section copy
Simplified hero section messaging:
- Changed subtitle from 'Level up your mental math powers...' to
  'Classic strategy games and lightning-fast challenges'
- Removed outdated feature pills (xpBadge, streakBadge, features)
- More accurate description of current game offerings

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 07:04:09 -06:00
Thomas Hallock
82c133f742 refactor(games): implement carousel, fix victories bug, add conditional stats
This commit includes several related improvements to the games page:

1. Fix victories calculation - removed incorrect division by player count
2. Implement player profile carousel using embla-carousel-react
   - Smooth infinite loop carousel with drag support
   - Navigation dots with player emojis
   - Simple opacity-based transitions (no 3D effects)
   - Disabled text selection during drag
   - Fixed gap spacing at carousel wrap point
3. Add conditional rendering - hide stats sections when user has no gameplay data
4. Update hero section - simplified design, removed excessive animations
5. Switch to PageWithNav for consistent navigation across the app

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 07:04:09 -06:00
Thomas Hallock
642ae95738 feat: install embla-carousel-react for player profile carousel
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>
2025-11-03 07:04:09 -06:00