Compare commits

...

152 Commits

Author SHA1 Message Date
semantic-release-bot
3564bd51dc chore(release): 4.48.2 [skip ci]
## [4.48.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.48.1...v4.48.2) (2025-10-20)

### Bug Fixes

* **nav:** ensure nav bar appears above tutorial tooltips ([cc31564](cc315645de))

### Styles

* **hero:** unify background with rest of homepage ([035d831](035d8312c7))
2025-10-20 21:00:17 +00:00
Thomas Hallock
cc315645de fix(nav): ensure nav bar appears above tutorial tooltips
Increased navigation bar z-index from 30 to 1000 to ensure it remains
above tutorial tooltips (which use z-index 50 and 100) when scrolling.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 15:58:58 -05:00
Thomas Hallock
035d8312c7 style(hero): unify background with rest of homepage
Replace purple gradient with solid gray.900 background to eliminate
sharp transition between hero section and page content.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 15:52:33 -05:00
semantic-release-bot
5f9b2dfe2b chore(release): 4.48.1 [skip ci]
## [4.48.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.48.0...v4.48.1) (2025-10-20)

### Bug Fixes

* **hero:** prevent SSR hydration mismatch for subtitle ([1bfde8f](1bfde8fb25))
2025-10-20 19:31:27 +00:00
Thomas Hallock
1bfde8fb25 fix(hero): prevent SSR hydration mismatch for subtitle
Add isSubtitleLoaded flag to hide subtitle until client-side random
selection completes, preventing flash of wrong subtitle during hydration.

Changes:
- Add isSubtitleLoaded state to HomeHeroContext
- Set flag to true after subtitle is selected on client
- Add opacity transition to subtitle in HeroAbacus
- Matches loading pattern used for abacus value

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 14:30:21 -05:00
semantic-release-bot
48647e4fb5 chore(release): 4.48.0 [skip ci]
## [4.48.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.47.2...v4.48.0) (2025-10-20)

### Features

* **hero:** persist random subtitle per-session ([318f946](318f9469a0))
2025-10-20 19:20:03 +00:00
Thomas Hallock
318f9469a0 feat(hero): persist random subtitle per-session
Store the randomly selected subtitle index in sessionStorage so it
remains consistent throughout the user's session. This eliminates
subtitle flashing on page reloads and provides a more stable UX.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 14:18:31 -05:00
semantic-release-bot
4bace36561 chore(release): 4.47.2 [skip ci]
## [4.47.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.47.1...v4.47.2) (2025-10-20)

### Bug Fixes

* **nav:** prevent thrashing by using fixed position always ([eff44b3](eff44b3ad1))
* **nav:** remove unnecessary borders from transparent nav ([8c2ddca](8c2ddca28d))
2025-10-20 19:16:22 +00:00
Thomas Hallock
8c2ddca28d fix(nav): remove unnecessary borders from transparent nav
Remove borders and extra padding around navigation elements when in
transparent mode. The borders were appearing as black and cluttering
the clean transparent overlay look. Now navigation elements show only
white text without any borders.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 14:14:59 -05:00
Thomas Hallock
eff44b3ad1 fix(nav): prevent thrashing by using fixed position always
The thrashing was caused by a layout shift feedback loop: switching
between position sticky (takes up space) and position fixed (overlays)
caused content to shift, triggering IntersectionObserver again.

Fix: Always use position fixed so nav state changes are purely visual
(transparency, borders, colors) without any layout shifts.

Also removed unnecessary hysteresis code since the root cause is fixed.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 14:13:54 -05:00
semantic-release-bot
f81b88ae30 chore(release): 4.47.1 [skip ci]
## [4.47.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.47.0...v4.47.1) (2025-10-20)

### Bug Fixes

* **hero:** prevent nav thrashing with hysteresis ([71b1b93](71b1b933b5))
2025-10-20 19:11:07 +00:00
Thomas Hallock
71b1b933b5 fix(hero): prevent nav thrashing with hysteresis
Add hysteresis to IntersectionObserver to prevent rapid toggling
between transparent and opaque nav bar states when scrolling near
the threshold. Now uses different thresholds for hiding (< 10%) vs
showing (> 30%), creating a 20% buffer zone.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 14:09:51 -05:00
semantic-release-bot
92d50673e5 chore(release): 4.47.0 [skip ci]
## [4.47.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.46.2...v4.47.0) (2025-10-20)

### Features

* **nav:** add transparent nav bar with borders when hero visible ([463841e](463841e191))

### Bug Fixes

* **hero:** use Number.isNaN instead of global isNaN ([c229faf](c229faffac))

### Styles

* **hero-abacus:** add purple bead colors for dark theme ([721dfe4](721dfe426d))
* **hero:** adjust spacing between title, subtitle, and abacus ([3a3706c](3a3706cc6f))
2025-10-20 19:04:17 +00:00
Thomas Hallock
c229faffac fix(hero): use Number.isNaN instead of global isNaN
Replace unsafe global isNaN with Number.isNaN to fix linting warning
and follow best practices for type coercion checking.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 14:02:59 -05:00
Thomas Hallock
463841e191 feat(nav): add transparent nav bar with borders when hero visible
When the hero section is visible on the homepage, the navigation bar
now becomes transparent with a fixed position overlay, featuring
contrasting white borders around nav elements for visibility. The nav
links change to white text for better contrast against the dark hero
background.

When scrolling past the hero, the nav returns to its normal white
background with sticky positioning.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 14:02:52 -05:00
Thomas Hallock
3a3706cc6f style(hero): adjust spacing between title, subtitle, and abacus
Reduce gap between title and subtitle from 4 to 2, and add margin
below subtitle to increase space before the abacus for better visual
hierarchy.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 14:02:43 -05:00
Thomas Hallock
721dfe426d style(hero-abacus): add purple bead colors for dark theme
Previously only styled column posts and reckoning bar, leaving
bright default bead colors that clashed with dark background.

Added:
- Heaven beads: light purple rgba(196, 181, 253, 0.8)
- Earth beads: medium purple rgba(167, 139, 250, 0.7)
- Both with violet strokes for definition

Beads now blend harmoniously with the dark purple gradient background.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 13:05:11 -05:00
semantic-release-bot
9dba75c9d9 chore(release): 4.46.2 [skip ci]
## [4.46.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.46.1...v4.46.2) (2025-10-20)

### Bug Fixes

* **types:** properly type HomeHeroContext in AppNavBar ([f9a7cb7](f9a7cb7f05))
2025-10-20 18:03:17 +00:00
Thomas Hallock
f9a7cb7f05 fix(types): properly type HomeHeroContext in AppNavBar
TypeScript error: Context type was incorrectly inferred when using
fallback React.createContext(null), causing type mismatch.

Solution: Add explicit HomeHeroContextValue type and cast both the
dynamically loaded context and the fallback to this type.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 13:01:59 -05:00
semantic-release-bot
ae7463d917 chore(release): 4.46.1 [skip ci]
## [4.46.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.46.0...v4.46.1) (2025-10-20)

### Bug Fixes

* **hero-abacus:** restructure layout to prevent visual overlap ([02b6c70](02b6c70b7a))
2025-10-20 17:59:13 +00:00
Thomas Hallock
02b6c70b7a fix(hero-abacus): restructure layout to prevent visual overlap
Problem: Title, subtitle, and scaled abacus were stacking too tightly,
creating visual overlap and a messy appearance.

Solution: Reorganize with space-between flexbox layout:
- Group title + subtitle together at top with compact spacing
- Give abacus its own centered flex container with generous padding
- Separate scroll hint at bottom
- Use vertical padding and flex: 1 to ensure proper spacing

This creates clear visual separation between all sections.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 12:58:05 -05:00
semantic-release-bot
4b72e0c561 chore(release): 4.46.0 [skip ci]
## [4.46.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.45.0...v4.46.0) (2025-10-20)

### Features

* **homepage:** add full-page hero abacus with scroll-based nav transition ([d8ec642](d8ec64280e))

### Bug Fixes

* **homepage:** improve hero abacus sizing and layout ([230f1dc](230f1dcd86))

### Styles

* **hero-abacus:** apply dark theme to match homepage styling ([e0b6a2e](e0b6a2e88b))
2025-10-20 17:57:21 +00:00
Thomas Hallock
e0b6a2e88b style(hero-abacus): apply dark theme to match homepage styling
Add dark mode custom styles for column posts and reckoning bar:
- Semi-transparent white fills (0.3-0.4 opacity)
- Subtle stroke borders (0.2-0.25 opacity)
- Matches styling used in MiniAbacus component

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 12:56:13 -05:00
Thomas Hallock
230f1dcd86 fix(homepage): improve hero abacus sizing and layout
Improvements:
- Increase hero abacus size: 2x→3x→4x scale for mobile/tablet/desktop
- Add better spacing between subtitle and abacus (mb: 16)
- Add z-index layering to prevent subtitle/abacus overlap
- Fix nav layout issue by adding spacer div when branding is hidden
- Remove emoji from hero title (redundant with actual abacus)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 12:55:01 -05:00
Thomas Hallock
d8ec64280e feat(homepage): add full-page hero abacus with scroll-based nav transition
Implement an immersive homepage experience with a large, interactive
4-column abacus that dominates the initial viewport, creating a
"play with this" first impression. The hero smoothly transitions
to reveal the Abaci One branding in the navigation when scrolled.

**New Components:**
- `HeroAbacus`: Full-viewport interactive abacus with title/subtitle
  - Auto-cycles through random 4-digit numbers
  - Responsive scaling (1.5x mobile, 2x tablet, 2.5x desktop)
  - Intersection Observer to track visibility

- `HomeHeroContext`: Shared state for subtitle and scroll visibility
  - SSR-safe random subtitle selection (client-side only)
  - Prevents hydration mismatch warnings
  - Shares abacus value across hero/nav

**Navigation Updates:**
- AppNavBar conditionally shows/hides branding based on hero visibility
- Smooth fadeIn animation when branding appears after scroll
- Uses same random subtitle from context (consistent across page)
- Optional context access without breaking other pages

**Mobile Support:**
- Responsive abacus scaling for all screen sizes
- Touch-friendly interactive abacus
- Smooth animations work on all devices

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 12:55:01 -05:00
semantic-release-bot
1d4419364a chore(release): 4.45.0 [skip ci]
## [4.45.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.44.3...v4.45.0) (2025-10-20)

### Features

* **branding:** rebrand navigation from 'Soroban Generator' to 'Abaci One' ([cce8980](cce8980e17))
2025-10-20 17:39:58 +00:00
Thomas Hallock
cce8980e17 feat(branding): rebrand navigation from 'Soroban Generator' to 'Abaci One'
Changes:
- Add new subtitle data file with 75 three-word rhyming options
- Update AppNavBar to display "🧮 Abaci One" with random subtitle
- Implement Radix UI tooltip showing subtitle description on hover
- Use useMemo for performance (subtitle won't change on re-renders)
- Clean, minimal design with italic subtitle and help cursor

Implementation:
- Created `/src/data/abaciOneSubtitles.ts` with subtitle data structure
- Updated AppNavBar imports to include Radix Tooltip and subtitle util
- Wrapped navigation in Tooltip.Provider with 200ms delay
- Logo displays vertically with brand name and subtitle
- Tooltip shows description like "blaze through bead races" on hover

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 12:38:38 -05:00
semantic-release-bot
4bcce2a8db chore(release): 4.44.3 [skip ci]
## [4.44.3](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.44.2...v4.44.3) (2025-10-20)

### Bug Fixes

* **levels:** reduce operator box sizes and remove divider line ([29d20a6](29d20a6c07))
* **levels:** use uniform padding on operator box grid ([2818fd1](2818fd15ca))
2025-10-20 16:40:18 +00:00
Thomas Hallock
2818fd15ca fix(levels): use uniform padding on operator box grid
- Replaced separate pl, pr, py with uniform p: '2'
- Ensures equal padding on all sides (left, right, top, bottom)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 11:39:09 -05:00
Thomas Hallock
29d20a6c07 fix(levels): reduce operator box sizes and remove divider line
- Reduced box dimensions from 200x180px to 170x150px for better fit
- Reduced grid gap from '3' to '2' for tighter layout
- Reduced box padding from '4' to '3' and gap from '2' to '1.5'
- Reduced maxW from 480px to 400px
- Changed my (margins) to py (padding) for more control
- Removed borderRight divider line between operator boxes and abacus

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 11:38:14 -05:00
semantic-release-bot
be2c3f63b0 chore(release): 4.44.2 [skip ci]
## [4.44.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.44.1...v4.44.2) (2025-10-20)

### Bug Fixes

* **levels:** match top/bottom margins to left padding on kyu detail boxes ([aa0bdcf](aa0bdcf686))
2025-10-20 16:37:17 +00:00
Thomas Hallock
aa0bdcf686 fix(levels): match top/bottom margins to left padding on kyu detail boxes
- Reduced my (vertical margins) from '6' to '2' to match pl (left padding)
- Ensures consistent spacing on all sides of the detail box grid

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 11:36:11 -05:00
semantic-release-bot
baea602000 chore(release): 4.44.1 [skip ci]
## [4.44.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.44.0...v4.44.1) (2025-10-20)

### Bug Fixes

* **levels:** add fixed dimensions and margins to kyu detail boxes ([05dd0b3](05dd0b30d3))
2025-10-20 16:35:46 +00:00
Thomas Hallock
05dd0b30d3 fix(levels): add fixed dimensions and margins to kyu detail boxes
- Set fixed width (200px) and height (180px) for operator boxes to prevent shifting
- Add vertical margins (my: 6) to grid container for better spacing
- Ensures boxes stay in consistent positions when sliding through levels
- Large enough to accommodate longest content (11 digits)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 11:34:32 -05:00
semantic-release-bot
4febf5905b chore(release): 4.44.0 [skip ci]
## [4.44.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.43.2...v4.44.0) (2025-10-20)

### Features

* **levels:** redesign kyu details with larger operators and prominent digits ([6739d59](6739d59f2b))
2025-10-20 16:31:02 +00:00
Thomas Hallock
6739d59f2b feat(levels): redesign kyu details with larger operators and prominent digits
- Increase operator icon size from xl to 4xl for better visibility
- Center-align card layout with operator icon at top
- Extract and prominently display digit count in 2xl bold text
- Change hover effect from slide to scale for centered design
- Increase base font size from sm to md

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 11:29:47 -05:00
semantic-release-bot
cb20019c16 chore(release): 4.43.2 [skip ci]
## [4.43.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.43.1...v4.43.2) (2025-10-20)

### Code Refactoring

* **levels:** remove Time and Pass sections from kyu details ([d90b5d5](d90b5d5532))
2025-10-20 16:29:27 +00:00
Thomas Hallock
d90b5d5532 refactor(levels): remove Time and Pass sections from kyu details
Remove the Time and Pass requirement cards since we don't have actual tests
implemented. Now only showing Add/Sub, Multiply, and Divide requirements.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 11:28:19 -05:00
semantic-release-bot
7028db0263 chore(release): 4.43.1 [skip ci]
## [4.43.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.43.0...v4.43.1) (2025-10-20)

### Bug Fixes

* **levels:** use two-column grid for kyu details to prevent clipping ([fa3b73c](fa3b73c691))
2025-10-20 16:28:08 +00:00
Thomas Hallock
fa3b73c691 fix(levels): use two-column grid for kyu details to prevent clipping
Change from single-column flex to two-column grid layout to avoid vertical
overflow. Increased max width to 480px to accommodate the wider layout.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 11:27:01 -05:00
semantic-release-bot
fd4d25c2d1 chore(release): 4.43.0 [skip ci]
## [4.43.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.42.1...v4.43.0) (2025-10-20)

### Features

* **levels:** add structured kyu exam details with card UI ([6501b07](6501b073b1))
2025-10-20 16:26:37 +00:00
Thomas Hallock
6501b073b1 feat(levels): add structured kyu exam details with card UI
Parse kyu level requirements into structured sections with icons and color-coded
labels. Display in clean card layout with hover effects. Maintain consistent
font sizing across all levels.

Features:
- Parse Japanese exam data into structured sections (Add/Sub, Multiply, Divide, Time, Pass)
- Icon-based visual hierarchy (, ✖️, , ⏱️, )
- Color-coded labels matching level colors
- Card UI with hover effects
- Consistent sizing for better readability

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 11:25:34 -05:00
semantic-release-bot
9b4d9c21df chore(release): 4.42.1 [skip ci]
## [4.42.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.42.0...v4.42.1) (2025-10-20)

### Code Refactoring

* **levels:** store kyu data verbatim, add formatting layer ([53d23f1](53d23f19bc))
2025-10-20 16:18:49 +00:00
Thomas Hallock
53d23f19bc refactor(levels): store kyu data verbatim, add formatting layer
Store level details exactly as provided from shuzan.jp (with Japanese
characters), then translate and format creatively in the display layer.

Changes:
- Restore verbatim data with 口, 字, 実+法, 法+商, 題
- Add formatKyuDetails() helper to translate on display
- Translate: 口→rows, 字→chars, 実+法→total, 法+商→total, 題→sets
- Use operator symbols: + / −, ×, ÷
- Maintain separation between data source and presentation

This approach keeps the original data intact while allowing creative
freedom in how we display it.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 11:17:43 -05:00
semantic-release-bot
6c14012b97 chore(release): 4.42.0 [skip ci]
## [4.42.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.41.0...v4.42.0) (2025-10-20)

### Features

* **levels:** add kyu level details display with English translations ([c650ffa](c650ffa193))
2025-10-20 16:16:03 +00:00
Thomas Hallock
c650ffa193 feat(levels): add kyu level details display with English translations
Add comprehensive exam requirements for each Kyu level displayed on
the left side of the abacus pane:

- Create kyuLevelDetails data file with English translations
- Display level details only for Kyu levels (hidden for Dan)
- Implement responsive font sizing based on abacus size
- Center abacus for Dan levels, right-align for Kyu
- Format details in clean, readable layout with bullet points

Details include:
- Addition/Subtraction requirements (rows, characters)
- Multiplication/Division requirements (digit counts, problem counts)
- Exam time limits and passing scores

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 11:14:50 -05:00
semantic-release-bot
28834e8a3e chore(release): 4.41.0 [skip ci]
## [4.41.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.40.1...v4.41.0) (2025-10-20)

### Features

* **levels:** right-align abacus display ([8681b17](8681b17340))
2025-10-20 16:10:19 +00:00
Thomas Hallock
8681b17340 feat(levels): right-align abacus display
Change abacus display container from center to right-aligned layout for
better visual balance on the levels page.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 11:09:14 -05:00
semantic-release-bot
d52cc608eb chore(release): 4.40.1 [skip ci]
## [4.40.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.40.0...v4.40.1) (2025-10-20)

### Bug Fixes

* **levels:** increase animation speed to 10ms for 10th Dan ([6f89d9e](6f89d9e274))
2025-10-20 16:00:14 +00:00
Thomas Hallock
6f89d9e274 fix(levels): increase animation speed to 10ms for 10th Dan
Update animation speed progression to be more dramatic, reaching 10ms
(0.01 seconds) at 10th Dan instead of 50ms. Speed progression now runs
from 1st Dan to 10th Dan (not from Pre-1st Dan).

Speed progression:
- Kyu levels: 500ms (constant)
- Pre-1st Dan: 500ms
- 1st Dan: 500ms
- 10th Dan: 10ms
- Linear interpolation between 1st and 10th Dan

This creates an extremely fast blur effect at the highest mastery level,
better representing the extraordinary calculation speed expected at 10th Dan.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 10:58:59 -05:00
semantic-release-bot
a8cc2bc0f0 chore(release): 4.40.0 [skip ci]
## [4.40.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.39.1...v4.40.0) (2025-10-20)

### Features

* **levels:** progressive animation speed for Dan levels ([9dff3e7](9dff3e7b7b))
2025-10-20 15:58:36 +00:00
Thomas Hallock
9dff3e7b7b feat(levels): progressive animation speed for Dan levels
Increase abacus animation speed as Dan levels advance, creating a visual
representation of increasing mastery and speed. Animation interval changes
from 500ms at Kyu/Pre-1st Dan to 50ms at 10th Dan.

Changes:
- Kyu levels (10th-1st): constant 500ms animation interval
- Dan levels: linear interpolation from 500ms to 50ms
- Pre-1st Dan (index 10): 500ms
- 10th Dan (index 20): 50ms
- Effect now depends on currentIndex to update interval dynamically
- Add getAnimationInterval() helper for calculating speed

This creates a dramatic visual effect where the abacus becomes a blur of
movement at the highest mastery levels.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 10:57:31 -05:00
semantic-release-bot
92fedb698d chore(release): 4.39.1 [skip ci]
## [4.39.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.39.0...v4.39.1) (2025-10-20)

### Bug Fixes

* **levels:** improve slider tick spacing to use full width ([1e90d6c](1e90d6c620))
2025-10-20 15:54:04 +00:00
Thomas Hallock
1e90d6c620 fix(levels): improve slider tick spacing to use full width
Remove horizontal padding (90px) from tick marks container to allow emoji
tick marks to spread across the full width of the slider. This provides
better visual distribution of level indicators.

Changes:
- Change px from '90px' to '0' on tick marks container
- Tick marks now use space-between across full slider width

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 10:52:56 -05:00
semantic-release-bot
5fcb7925eb chore(release): 4.39.0 [skip ci]
## [4.39.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.38.1...v4.39.0) (2025-10-20)

### Features

* **levels:** add auto-advance slider with hover pause ([41eaed2](41eaed24fc))
2025-10-20 15:49:37 +00:00
Thomas Hallock
41eaed24fc feat(levels): add auto-advance slider with hover pause
Add automatic slider progression that advances one level every 3 seconds,
cycling back to the start when reaching the end. The auto-advance pauses
when the user's mouse is over the pane containing the slider and abacus,
allowing for manual exploration without interruption.

Changes:
- Add isPaneHovered state to track mouse position
- Add auto-advance effect with 3-second interval
- Pause auto-advance when isPaneHovered is true
- Add onMouseEnter/onMouseLeave handlers to pane container
- Cycle position back to 0 when reaching the last level

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 10:48:22 -05:00
semantic-release-bot
de5f36481b chore(release): 4.38.1 [skip ci]
## [4.38.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.38.0...v4.38.1) (2025-10-20)

### Bug Fixes

* **levels:** adjust slider text positioning to prevent emoji overlap ([e5ffe39](e5ffe3927e))
2025-10-20 15:46:10 +00:00
Thomas Hallock
e5ffe3927e fix(levels): adjust slider text positioning to prevent emoji overlap
Move level text further down (bottom: -80px) to prevent it from overlapping
with emoji characters. Previous positioning (-60px) was too close for Dan
level emojis, causing the text to cover the characters' chins.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 10:45:09 -05:00
semantic-release-bot
7c47fcdc54 chore(release): 4.38.0 [skip ci]
## [4.38.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.37.0...v4.38.0) (2025-10-20)

### Features

* **levels:** add animated calculation effect to abacus display ([4f4c735](4f4c73577a))
2025-10-20 15:42:45 +00:00
Thomas Hallock
4f4c73577a feat(levels): add animated calculation effect to abacus display
Add visual animation to the levels page abacus that simulates ongoing
calculations by randomly changing 1-3 adjacent columns every 0.5 seconds.
This creates a more dynamic, engaging visual that shows the abacus "working"
as users explore different skill levels.

Changes:
- Add animatedDigits state to track current digit values
- Initialize random digits when level changes
- Add interval effect to update 1-3 adjacent columns every 500ms
- Use animated digits instead of static pattern for AbacusReact display
- Adjacent column grouping simulates realistic calculation movements

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 10:40:42 -05:00
semantic-release-bot
1e6459f9c1 chore(release): 4.37.0 [skip ci]
## [4.37.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.36.0...v4.37.0) (2025-10-20)

### Features

* **levels:** add hover tracking to slider for real-time level preview ([477a0b3](477a0b367e))
2025-10-20 15:35:35 +00:00
Thomas Hallock
477a0b367e feat(levels): add hover tracking to slider for real-time level preview
Added mouse hover functionality to the slider so it responds as you move
your mouse across the track:
- Calculates hover position based on mouse X coordinate
- Updates slider value in real-time as you hover
- Tracks hover state with isHovering flag
- Slider thumb follows your mouse smoothly with CSS transitions

Now you can explore levels by simply hovering across the slider track,
in addition to clicking emoji tick marks or dragging the thumb.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 10:34:25 -05:00
semantic-release-bot
8751649233 chore(release): 4.36.0 [skip ci]
## [4.36.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.35.1...v4.36.0) (2025-10-20)

### Features

* **levels:** make emoji tick marks clickable and remove redundant UI ([07c783a](07c783a794))

### Bug Fixes

* **levels:** add smooth CSS transitions for slider thumb movement ([ca8cef1](ca8cef1c36))
2025-10-20 15:32:54 +00:00
Thomas Hallock
07c783a794 feat(levels): make emoji tick marks clickable and remove redundant UI
- Added click handlers to emoji tick marks so you can click any emoji to jump to that level
- Added hover effects (opacity 0.6) and pointer cursor to tick marks
- Enabled pointer events on tick marks (parent has pointerEvents: 'none')
- Removed redundant "Drag or click the beads" instruction text
- Removed duplicated level info text below slider (info now only shows on slider thumb)

This simplifies the UI and makes the slider more interactive - you can now
click, drag, or hover over any emoji to explore different levels.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 10:31:40 -05:00
Thomas Hallock
ca8cef1c36 fix(levels): add smooth CSS transitions for slider thumb movement
Fixed slider transitions to be smooth but responsive:
- Balanced animation speeds (scale: tension 350/friction 45, emoji: 120ms)
- Added 0.3s CSS transition specifically for thumb position (left property)
- Removed complex React Spring state management that wasn't triggering re-renders
- Simplified to basic state management with CSS handling the smoothness

This gives a nice gliding effect when clicking between levels while
keeping the interface snappy and responsive.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 10:31:40 -05:00
semantic-release-bot
0d47664f9f chore(release): 4.35.1 [skip ci]
## [4.35.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.35.0...v4.35.1) (2025-10-20)

### Features

* **abacus-react:** export StandaloneBead component wired to AbacusDisplayContext ([0146ce1](0146ce1e67))

### Performance Improvements

* **levels:** speed up slider animations for more responsive feel ([1e5467f](1e5467fad4))
2025-10-20 15:25:06 +00:00
Thomas Hallock
1e5467fad4 perf(levels): speed up slider animations for more responsive feel
Reduced animation timing across the board to make the slider feel snappier:
- Scale factor animation: increased tension (280→400), reduced friction (60→40)
- Emoji cross-fade: reduced duration from 150ms to 80ms
- Thumb hover: reduced transition from 0.2s to 0.1s with ease-out

This addresses user feedback that the slider felt sluggish.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 10:23:46 -05:00
semantic-release-bot
44f8b27fa1 chore(abacus-react): release v2.1.0 [skip ci]
# [2.1.0](https://github.com/antialias/soroban-abacus-flashcards/compare/abacus-react-v2.0.0...abacus-react-v2.1.0) (2025-10-20)

### Bug Fixes

* **levels:** add fixed height to entire level display pane ([200b26c](200b26c2cd))
* **levels:** increase container height to prevent abacus clipping ([cd5c15a](cd5c15aeb2))
* **levels:** only animate abacus, not container with background/border ([c80477d](c80477d248))
* **levels:** reduce Dan scale and container height to prevent clipping ([563136f](563136fb79))
* **levels:** reduce max scale factor to allow more compact container ([ead9ee9](ead9ee9589))
* **levels:** reduce scale factor variation to minimize margin differences ([abb647c](abb647ce40))
* **levels:** revert delayed column change, keep overflow hidden ([22f00f5](22f00f59f5))
* **levels:** stabilize slider position and prevent abacus clipping ([09004dc](09004dc2c0))

### Features

* **abacus-react:** export StandaloneBead component wired to AbacusDisplayContext ([0146ce1](0146ce1e67))
* **levels:** add hover interaction and smooth React Spring transitions ([fd2b633](fd2b6338a8))
* **levels:** redesign slider with abacus-themed beads ([f3dce84](f3dce84532))
* **levels:** replace slider thumb with diamond-shaped abacus beads ([0fbde53](0fbde53039))
2025-10-20 14:31:30 +00:00
Thomas Hallock
0146ce1e67 feat(abacus-react): export StandaloneBead component wired to AbacusDisplayContext
feat(levels): use StandaloneBead for slider thumb and decorative tick beads

fix(levels): make slider background transparent to prevent abacus clipping

Created StandaloneBead component that integrates with the abacus style context,
replacing hardcoded SVG diamonds with proper context-aware bead rendering.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 09:28:41 -05:00
semantic-release-bot
acfb0dac0a chore(release): 4.35.0 [skip ci]
## [4.35.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.34.0...v4.35.0) (2025-10-20)

### Features

* **levels:** replace slider thumb with diamond-shaped abacus beads ([0fbde53](0fbde53039))
2025-10-20 14:21:41 +00:00
Thomas Hallock
0fbde53039 feat(levels): replace slider thumb with diamond-shaped abacus beads
Replaced circular slider elements with proper diamond-shaped beads that
match the authentic abacus bead style:

**Slider Thumb (Drag Handle)**:
- Diamond SVG polygon matching AbacusReact bead geometry
- 28x28px size for easy grabbing
- Two-layer design: outer diamond + inner highlight for depth
- Black stroke (0.8px) matching abacus bead styling
- Color-coded: violet for Dan levels, green for Kyu levels
- Maintains grab/grabbing cursor states

**Decorative Tick Beads**:
- All 40 level markers now use diamond shapes instead of circles
- Sized 8px (inactive) to 14px (active)
- Same color scheme and styling as main beads
- Proper stroke colors matching active/inactive states
- Drop-shadow filter for active bead glow effect

This creates a cohesive visual language connecting the interactive
slider to the abacus display, making the page feel more integrated
and true to the abacus aesthetic.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 09:20:33 -05:00
semantic-release-bot
90bbe6fbb7 chore(release): 4.34.0 [skip ci]
## [4.34.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.33.8...v4.34.0) (2025-10-20)

### Features

* **levels:** redesign slider with abacus-themed beads ([f3dce84](f3dce84532))

### Code Refactoring

* **levels:** convert to Radix UI Slider with abacus theme ([a03e73c](a03e73c849))
2025-10-20 14:16:55 +00:00
Thomas Hallock
a03e73c849 refactor(levels): convert to Radix UI Slider with abacus theme
Replaced custom HTML input slider with Radix UI Slider for better
accessibility and consistency with the rest of the application.

Key changes:
- Integrated @radix-ui/react-slider for proper a11y support
- Maintained abacus-themed visual design with bead ticks
- Larger interactive area (h: '12' / 48px) for easier interaction
- Color-coded beads (green for Kyu, violet for Dan)
- Interactive thumb styled as a prominent bead with grab cursor
- Decorative beads for all 40 levels with pointer-events: none
- Smooth transitions and hover effects on thumb
- Removed custom hover handler in favor of Radix's built-in interaction

This provides a more robust and accessible slider while maintaining
the unique abacus aesthetic.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 09:15:46 -05:00
Thomas Hallock
f3dce84532 feat(levels): redesign slider with abacus-themed beads
Replaced standard slider with custom abacus-themed design:
- Added bead-like circular ticks for all 40 levels
- Color-coded beads (green for Kyu, violet for Dan)
- Active bead glows and scales up (16px) with shadow effect
- Inactive beads are semi-transparent (12px)
- Increased hit target with vertical padding (py: '6')
- Added horizontal "reckoning bar" as the track
- Smooth transitions on bead state changes

This creates a more forgiving hover/drag experience and prevents
confusion from minor cursor deviations while interacting.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 09:13:26 -05:00
semantic-release-bot
3b6284ae18 chore(release): 4.33.8 [skip ci]
## [4.33.8](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.33.7...v4.33.8) (2025-10-20)

### Bug Fixes

* **levels:** reduce Dan scale and container height to prevent clipping ([563136f](563136fb79))
* **levels:** reduce max scale factor to allow more compact container ([ead9ee9](ead9ee9589))
2025-10-20 14:13:05 +00:00
Thomas Hallock
563136fb79 fix(levels): reduce Dan scale and container height to prevent clipping
Changed minimum scale factor from 1.5 to 1.2 for 30-column Dan abacuses
to prevent leftmost/rightmost columns from being clipped. Also reduced
container height from 900px to 700px to provide better visual balance
without excessive whitespace around the largest Kyu abacus.

Scale factor range is now 1.2 to 2.0, creating a 1.67x size difference.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 09:11:59 -05:00
Thomas Hallock
ead9ee9589 fix(levels): reduce max scale factor to allow more compact container
Changed maximum scale factor from 3.0 to 2.0 for small Kyu abacuses.
This allows for a more compact fixed-height container while still
providing appropriate visual scaling across all levels.

Scale factor range is now 1.5 to 2.0, creating a 1.33x size difference
instead of the previous 2.0x difference.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 09:10:20 -05:00
semantic-release-bot
a12ae969be chore(release): 4.33.7 [skip ci]
## [4.33.7](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.33.6...v4.33.7) (2025-10-20)

### Bug Fixes

* **levels:** reduce scale factor variation to minimize margin differences ([abb647c](abb647ce40))
2025-10-20 14:08:00 +00:00
Thomas Hallock
abb647ce40 fix(levels): reduce scale factor variation to minimize margin differences
Changed scale factor formula to use a constrained range (1.5 to 3.0)
instead of the previous unbounded formula that allowed much wider variation.

Previous formula: Math.min(2.5, 20 / digits)
- 2 columns (10 Kyu): 2.5
- 30 columns (Dan): 0.67
- Ratio: ~3.7x difference

New formula: Math.max(1.5, Math.min(3.0, 20 / digits))
- 2 columns (10 Kyu): 3.0
- 30 columns (Dan): 1.5
- Ratio: 2.0x difference

This reduces the excessive margin around Dan level abacuses while still
providing appropriate scaling for different column counts.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 09:06:46 -05:00
semantic-release-bot
d6c28f7ede chore(release): 4.33.6 [skip ci]
## [4.33.6](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.33.5...v4.33.6) (2025-10-20)

### Bug Fixes

* **levels:** increase container height to prevent abacus clipping ([cd5c15a](cd5c15aeb2))
2025-10-20 14:04:50 +00:00
Thomas Hallock
cd5c15aeb2 fix(levels): increase container height to prevent abacus clipping
Increased the main level display container height from 700px to 900px
to provide more vertical space for the abacus display.

This prevents the top and bottom of the abacus from being clipped,
especially for levels with larger column counts.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 09:03:41 -05:00
semantic-release-bot
ccaad3abc8 chore(release): 4.33.5 [skip ci]
## [4.33.5](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.33.4...v4.33.5) (2025-10-20)

### Bug Fixes

* **levels:** revert delayed column change, keep overflow hidden ([22f00f5](22f00f59f5))
2025-10-20 14:03:23 +00:00
Thomas Hallock
22f00f59f5 fix(levels): revert delayed column change, keep overflow hidden
Reverted the delayed column change approach (using displayedIndex state
and onRest callback) which was causing bugs. Went back to the simpler
direct approach where currentIndex immediately drives all changes.

Changes:
- Removed displayedIndex state and displayedLevel variable
- Removed onRest callback from React Spring configuration
- All UI elements now use currentLevel directly
- Kept overflow: 'hidden' on abacus container

The simpler approach provides better UX with immediate feedback while
React Spring still provides smooth scale transitions.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 09:02:19 -05:00
semantic-release-bot
a85815fdf9 chore(release): 4.33.4 [skip ci]
## [4.33.4](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.33.3...v4.33.4) (2025-10-20)

### Bug Fixes

* **levels:** stabilize slider position and prevent abacus clipping ([09004dc](09004dc2c0))
2025-10-20 13:58:06 +00:00
Thomas Hallock
09004dc2c0 fix(levels): stabilize slider position and prevent abacus clipping
Fixed three layout issues with the levels page slider interaction:

1. Fixed height for level info section (160px with flexbox centering)
   - Prevents slider from shifting vertically when switching between Kyu
     and Dan levels (Dan levels have extra text for name + minScore)
   - Keeps slider position stable during hover interaction

2. Changed abacus container overflow from 'auto' to 'visible'
   - Prevents abacus from being clipped at container boundaries
   - Allows full abacus display without scrollbars

3. Reduced spacing between sections for better layout balance

These changes ensure the slider stays perfectly under the mouse cursor
during hover interaction while the abacus smoothly animates.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 08:56:57 -05:00
semantic-release-bot
22c8a57a16 chore(release): 4.33.3 [skip ci]
## [4.33.3](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.33.2...v4.33.3) (2025-10-20)

### Code Refactoring

* **levels:** move slider into level display pane above abacus ([2d8bb4a](2d8bb4ab88))
2025-10-20 13:51:02 +00:00
Thomas Hallock
2d8bb4ab88 refactor(levels): move slider into level display pane above abacus
Relocate the slider control from a separate container below the level
display to inside the level pane itself, positioned above the abacus.

Changes:
- Move slider markup into main level display pane
- Position between level info and abacus display
- Remove separate slider container that was below
- Adjust spacing for better visual hierarchy

Improves UX by keeping the control close to the content it affects.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 08:49:59 -05:00
semantic-release-bot
8e345cfb4c chore(release): 4.33.2 [skip ci]
## [4.33.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.33.1...v4.33.2) (2025-10-20)

### Bug Fixes

* **levels:** add fixed height to entire level display pane ([200b26c](200b26c2cd))
2025-10-20 13:46:27 +00:00
Thomas Hallock
200b26c2cd fix(levels): add fixed height to entire level display pane
Fix slider hover interaction by making the entire level display pane
(including level info, abacus, and digit count) a fixed height. This
prevents the slider from moving when hovering over it.

Changes:
- Add fixed height of 700px on desktop (auto on mobile) to level pane
- Convert container to flexbox with column direction
- Make abacus display area flex: 1 to fill remaining space
- Slider now stays perfectly still under mouse during hover

This makes the hover interaction much more usable - you can now smoothly
move your mouse across the slider without it jumping away.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 08:45:17 -05:00
semantic-release-bot
66e38af457 chore(release): 4.33.1 [skip ci]
## [4.33.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.33.0...v4.33.1) (2025-10-20)

### Bug Fixes

* **levels:** only animate abacus, not container with background/border ([c80477d](c80477d248))
2025-10-20 13:44:30 +00:00
Thomas Hallock
c80477d248 fix(levels): only animate abacus, not container with background/border
Fix React Spring animation to only affect the abacus itself, not the
container with background and border. Also keep container height fixed.

Changes:
- Move animation from container div to inner wrapper around AbacusReact
- Add minHeight to container to prevent height changes
- Add alignItems: 'center' to vertically center the abacus
- Container background/border now stays fixed while abacus animates

This provides a cleaner, more polished animation where only the abacus
scales smoothly while the container remains stable.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 08:43:24 -05:00
semantic-release-bot
9a688c1574 chore(release): 4.33.0 [skip ci]
## [4.33.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.32.1...v4.33.0) (2025-10-20)

### Features

* **abacus-react:** add BigInt support for 30-digit Dan level abacuses ([0ab4cc2](0ab4cc2880))
* **levels:** add hover interaction and smooth React Spring transitions ([fd2b633](fd2b6338a8))
2025-10-20 13:43:10 +00:00
Thomas Hallock
fd2b6338a8 feat(levels): add hover interaction and smooth React Spring transitions
Add hover/touch support and smooth animations to the levels page slider
for an enhanced interactive experience.

Changes:
- Add hover/touch move handlers to slider for instant level preview
- Integrate React Spring for smooth scale transitions between levels
- Animate abacus container with smooth scale transformations
- Support both mouse and touch events for mobile compatibility
- Update UI text to mention hover, drag, and touch interactions

The slider now responds immediately to mouse/touch position, making it
easy to explore different levels by simply hovering over the slider.
React Spring provides smooth transitions when switching between levels
with different abacus sizes.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 08:41:58 -05:00
semantic-release-bot
2cfde18414 chore(abacus-react): release v2.0.0 [skip ci]
# [2.0.0](https://github.com/antialias/soroban-abacus-flashcards/compare/abacus-react-v1.8.0...abacus-react-v2.0.0) (2025-10-20)

### Bug Fixes

* add dark color for abacus numerals ([73ff32c](73ff32c243)), closes [#1f2937](https://github.com/antialias/soroban-abacus-flashcards/issues/1f2937)
* add POST handler for join requests API endpoint ([d3e5cdf](d3e5cdfc54))
* add Typst to Docker image for flashcard generation ([d9a7694](d9a7694031))
* allow join with pending invitation for restricted rooms ([85b2cf9](85b2cf9816))
* allow password retry when joining via share link ([e469363](e469363699))
* **api:** add 'math-sprint' to settings endpoint validation ([d790e5e](d790e5e278)), closes [#1](https://github.com/antialias/soroban-abacus-flashcards/issues/1)
* **api:** include members and memberPlayers in room creation response ([8320d9e](8320d9e730))
* **arcade-rooms:** navigate to invite link after room creation ([1922b21](1922b2122b))
* **arcade:** add defensive checks and update test fixtures ([a93d981](a93d981d1a))
* **arcade:** add host-only game selection with clear messaging ([22df1b0](22df1b0b66))
* **arcade:** add host-only game selection with clear messaging ([c0680ca](c0680cad0f))
* **arcade:** add Number Guesser to game config helpers ([7d1a351](7d1a351ed6))
* **arcade:** allow room creator to rejoin restricted/approval rooms ([654ba19](654ba19ccc))
* **arcade:** delete old session when room game changes ([98a3a25](98a3a2573d))
* **arcade:** implement settings persistence for matching game ([08fe432](08fe4326a6))
* **arcade:** only notify room creator of join requests ([bc571e3](bc571e3d0d))
* **arcade:** preserve game settings when returning to game selection ([0ee7739](0ee7739091))
* **arcade:** preserve gameConfig when switching games ([2273c71](2273c71a87))
* **arcade:** prevent empty update in settings API when only gameConfig changes ([ffb626f](ffb626f403))
* **arcade:** prevent gameConfig from being overwritten when switching games ([a89d3a9](a89d3a9701))
* **arcade:** prevent server-side loading of React components ([784793b](784793ba24))
* **arcade:** read nested gameConfig correctly when creating sessions ([94ef392](94ef39234d))
* **arcade:** remove broken query param from game URLs ([87631af](87631af678))
* **arcade:** remove legacy master-organizer placeholder ([76d207e](76d207e2e5))
* **arcade:** resolve TypeScript errors in game config helpers ([04c9944](04c9944f2e))
* **build:** resolve Docker build failures preventing deployment ([7801dbb](7801dbb25f))
* **card-sorting:** center AbacusReact SVGs in card tiles ([26edec1](26edec1bbf))
* **card-sorting:** faithfully port UI/UX from Python original ([c92076f](c92076f232)), closes [#2c5f76](https://github.com/antialias/soroban-abacus-flashcards/issues/2c5f76) [#1976d2](https://github.com/antialias/soroban-abacus-flashcards/issues/1976d2)
* **card-sorting:** increase card tile sizes to contain abacuses ([d2a3b7a](d2a3b7ae2e))
* **card-sorting:** increase SVG size to fill card containers ([cf9d893](cf9d893f3f))
* **card-sorting:** match game selector background to other games ([db62519](db62519f9b)), closes [#ccfbf1](https://github.com/antialias/soroban-abacus-flashcards/issues/ccfbf1) [#99f6e4](https://github.com/antialias/soroban-abacus-flashcards/issues/99f6e4)
* **card-sorting:** match Python card layout with flex wrap ([9679d68](9679d68154))
* **card-sorting:** position slots flow horizontally with wrap ([e14ffe4](e14ffe44d6))
* **card-sorting:** use blue gradient matching other game cards ([bdb84f5](bdb84f5d90))
* clear hover state in CLEAR_MISMATCH for clean turn transitions ([43f7c92](43f7c92f6d))
* clear hover state on turn changes and game transitions ([6fd425c](6fd425ce85))
* **complement-race:** add missing AI commentary cooldown updates ([357aa30](357aa30618))
* **complement-race:** add missing useEffect import ([3054130](30541304dd))
* **complement-race:** add missing useRef import ([d43829a](d43829ad48))
* **complement-race:** add pressure decay system and improve logging ([66992e8](66992e8770))
* **complement-race:** balance AI speeds to match original implementation ([054f0c0](054f0c0d23))
* **complement-race:** clear input state on question transitions ([5872030](587203056a))
* **complement-race:** correct passenger boarding to use multiplayer fields ([7ed1b94](7ed1b94b8f))
* **complement-race:** counter-flip AI speech bubbles to make text readable ([07d5607](07d5607218))
* **complement-race:** flip AI racers to face right in practice mode ([ebfff1a](ebfff1a62f))
* **complement-race:** flip player avatar to face right in practice mode ([fa6b3b6](fa6b3b69d5))
* **complement-race:** implement client-side momentum with continuous decay for smooth train movement ([ea19ff9](ea19ff918b))
* **complement-race:** improve AI speech bubble positioning ([6e436db](6e436db5e7))
* **complement-race:** reduce initial momentum from 50 to 10 to prevent train sailing past first station ([5f146b0](5f146b0daf))
* **complement-race:** remove dual game loop conflict preventing route progression ([84d42e2](84d42e22ac))
* **complement-race:** resolve TypeScript errors in state adapter ([59abcca](59abcca4c4))
* **complement-race:** restore smooth train movement with client-side game loop ([46a80cb](46a80cbcc8))
* **complement-race:** show new passengers when route changes ([ec1c8ed](ec1c8ed263))
* **complement-race:** track physical car indices to prevent boarding issues ([53bbae8](53bbae84af))
* **complement-race:** track previous position to detect route threshold crossing ([a6c20aa](a6c20aab3b))
* **complement-race:** train now moves in sprint mode ([54b46e7](54b46e771e))
* **complement-race:** update passenger display when state changes ([5116364](511636400c))
* **complement-race:** use active local players pattern from navbar ([71cdc34](71cdc342c9))
* **complement-race:** use local player emoji instead of first active player ([76eb051](76eb0517c2))
* correct AbacusReact API usage and add structural styling ([247377f](247377fca3)), closes [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24) [#a78](https://github.com/antialias/soroban-abacus-flashcards/issues/a78)
* create arcade sessions on room join to enable config changes ([c29501f](c29501f666))
* **db:** add 'math-sprint' to database schema enums ([7b112a9](7b112a98ba)), closes [#1](https://github.com/antialias/soroban-abacus-flashcards/issues/1)
* **deployment:** pass git info to Docker build for deployment info modal ([4b04e43](4b04e43ff8))
* **docker:** add packages/templates for Typst flashcard generation ([1417722](1417722438))
* **docker:** add qpdf for PDF linearization and validation ([c92ff39](c92ff3971c))
* **docker:** bypass PEP 668 externally-managed-environment error ([bb59c61](bb59c61638))
* **docker:** copy core package with Python scripts to production image ([33e9ad2](33e9ad2f79))
* **docker:** include Panda CSS styled-system in production image ([57fabff](57fabffe60))
* **docker:** install py3-pip for Python dependency installation ([0f55909](0f55909533))
* **docker:** install Python dependencies for flashcard generation ([c9b7e92](c9b7e92f39))
* **docker:** remove reference to deleted @soroban/client package ([2953ef8](2953ef8917))
* exclude dist from TypeScript compilation and add missing type import ([b7f1d5a](b7f1d5a569))
* hide hover avatar for current user's own player ([dba42b5](dba42b5925))
* **homepage:** adjust mini abacus container height ([c4066d6](c4066d6879))
* **homepage:** correct positioning of progression arrows in Your Journey section ([3fff9ef](3fff9ef140))
* **homepage:** fix MiniAbacus runtime error and improve sizing ([1fa0df8](1fa0df85f7))
* **homepage:** improve text contrast in Your Journey section ([24d1200](24d120004d))
* **homepage:** use correct AbacusReact API and fix clipping/styling issues ([1432afd](1432afd6e6))
* **homepage:** use direct conditionals for mini abacus padding ([38ef16a](38ef16a8f9))
* **homepage:** use explicit RGBA colors for Your Journey text ([9c51cc9](9c51cc94ee))
* **homepage:** use inline styles for journey level colors ([5d85e89](5d85e898d6)), closes [#4ade80](https://github.com/antialias/soroban-abacus-flashcards/issues/4ade80) [#60a5](https://github.com/antialias/soroban-abacus-flashcards/issues/60a5) [#a78](https://github.com/antialias/soroban-abacus-flashcards/issues/a78) [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24)
* **homepage:** use inline styles for Your Journey text contrast ([8e51390](8e51390018)), closes [#e5e7](https://github.com/antialias/soroban-abacus-flashcards/issues/e5e7) [#e5e7](https://github.com/antialias/soroban-abacus-flashcards/issues/e5e7) [#9ca3](https://github.com/antialias/soroban-abacus-flashcards/issues/9ca3) [#d1d5](https://github.com/antialias/soroban-abacus-flashcards/issues/d1d5)
* **home:** use Panda CSS token() for dynamic colors and center arrows properly ([d52ba63](d52ba6373a))
* improve authorization error handling and add missing decline invitation endpoint ([97669ad](97669ad084))
* improve join request approval error handling with actionable messages ([57bf846](57bf8460c8))
* improve kicked modal message for retired room ejections ([f865ce1](f865ce16ec))
* join user socket channel to receive approval notifications ([7d08fdd](7d08fdd906))
* **levels:** use correct AbacusReact API with direct props ([892b377](892b377eb3))
* **levels:** use correct dark mode styling from homepage + docs update ([c38767f](c38767f4d3))
* **matching:** add settings persistence to matching game ([00dcb87](00dcb872b7))
* **matching:** apply turn indicators to arcade version too ([e6f96a8](e6f96a8b99))
* **matching:** make MemoryGrid generic to support different card types ([dcda826](dcda826b9a))
* **matching:** only apply turn indicator when game is active ([cb4c061](cb4c061d11))
* **matching:** replace mismatch banner with card shake animation ([804096f](804096fd8a))
* **matching:** use UUID instead of numeric index for scores ([5036cb0](5036cb00b6))
* **math-sprint:** remove unused import and autoFocus attribute ([51593eb](51593eb44f))
* **memory-quiz:** fix playMode persistence by updating validator ([de0efd5](de0efd5932))
* **memory-quiz:** persist playMode setting across game switches ([487ca7f](487ca7fba6))
* **memory-quiz:** prevent duplicate card processing from optimistic updates ([51676fc](51676fc15f))
* **memory-quiz:** prevent input lag during rapid typing in room mode ([b45139b](b45139b588))
* **memory-quiz:** scope game settings by game name for proper persistence ([3dfe54f](3dfe54f1cb))
* **memory-quiz:** synchronize card display across all players in multiplayer ([472f201](472f201088))
* **migrations:** add migration 0009 for display_password column ([040d749](040d7495a0))
* **moderation:** don't show pending invitation for users already in room ([fae5920](fae5920e2f))
* **moderation:** improve access mode settings UX ([dd9e657](dd9e657db8))
* move invitations into nav and filter out current/banned rooms ([cfaf82b](cfaf82b2cc))
* **nav:** add delay to hamburger menu hover to prevent premature closing ([95cd72e](95cd72e9bf))
* **nav:** add z-index to turn labels to prevent avatar overlap ([7c294da](7c294dafff))
* **nav:** close hamburger menu when nested dropdown closes and mouse not hovering ([7d65212](7d652126d0))
* **nav:** enable tooltips for local players during gameplay ([5499700](54997007b8))
* **nav:** improve readability of turn label text ([bbd1da0](bbd1da02b5))
* **nav:** improve text contrast in room info pane ([3e691cb](3e691cb06d))
* **nav:** navigate to /arcade/room (not /arcade/rooms/{id}) ([1c55f36](1c55f3630c))
* **nav:** navigate to room after creation from (+) menu ([21e6e33](21e6e33173))
* **nav:** prevent hamburger menu from closing when toggling Style dropdown ([a898fbc](a898fbc187))
* **nav:** prevent style dropdown from closing hamburger menu ([560a052](560a05266e))
* **nav:** prevent turn label text from being obscured ([c4b00dd](c4b00dd679))
* **nav:** properly prevent nested style dropdown from closing hamburger menu ([c5b6a82](c5b6a82ca4))
* **nav:** remove animation/enlargement from network player turn indicator ([53079ed](53079ede13))
* **nav:** remove blue gradient background from network players ([2881aff](2881affecc))
* **nav:** remove opacity reduction from local players ([5215af8](5215af801f))
* **nav:** remove play arrow badge from turn indicators ([80cfc10](80cfc10f78))
* **nav:** update types for registry games with nullable gameName ([a51e539](a51e539d02))
* **number-guesser:** add turn indicators, error feedback, and fix player ordering ([9f62623](9f62623684))
* pixel-perfect alignment across all nav elements ([fa78a2c](fa78a2c001))
* **player-config:** correct label positioning in player settings dialog ([554cc40](554cc4063b))
* populate session activePlayers from room members on join ([2d00939](2d00939f1b))
* prevent duplicate arcade sessions per room ([4cc3de5](4cc3de5f43))
* remove duplicate ModerationNotifications causing double toasts ([c6886a0](c6886a0e59))
* replace isLocked with accessMode and add bcryptjs ([a74b96b](a74b96bb6f))
* replace last remaining isLoading with isPending in CreateRoomModal ([85d13cc](85d13cc552))
* replace native alerts with inline confirmations in ModerationPanel ([ebe123e](ebe123ed7e))
* reset join request toast state when moderation event cleared ([6beb58a](6beb58a7b8))
* resolve Memory Quiz room-based multiplayer validation issues ([2ffeade](2ffeade437))
* resolve TypeScript errors in MemoryGrid and StandardGameLayout ([cabbc82](cabbc82195))
* **room-data:** update query cache when gameConfig changes ([7cea297](7cea297095))
* **rooms:** add real-time ownership transfer updates via WebSocket ([c00cfa3](c00cfa3de0))
* **room:** update GAME_TYPE_TO_NAME mapping for memory-quiz ([4afa171](4afa171af2))
* set color on abacus container div for numeral visibility ([cd47960](cd4796024e)), closes [#1f2937](https://github.com/antialias/soroban-abacus-flashcards/issues/1f2937)
* show initial value and improve numeral contrast ([1b57f6d](1b57f6ddec)), closes [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24)
* simplify abacus pane with light background ([30f48ab](30f48ab897))
* **socket-io:** update import path for socket-server module ([1a64dec](1a64decf5a))
* stack game title dropdown ABOVE room pane, not inside it ([7bc815f](7bc815fd7d))
* **toast:** scope animations to prevent affecting other UI elements ([245ed8a](245ed8a625))
* **tutorial:** correct column index calculation for variable column counts ([bf1ced4](bf1ced43f8))
* **tutorial:** filter bead highlights when using fewer columns ([4d906ec](4d906ec20e))
* **tutorial:** reduce tooltip z-index to scroll under nav bar ([47640f3](47640f3486))
* **tutorial:** resolve React hydration error in TutorialPlayer ([c883d9e](c883d9e4c1))
* **tutorial:** resolve TypeScript errors in TutorialPlayer ([88f57ce](88f57ce6df))
* **tutorial:** use correct customStyles API for dark mode frame styling ([fdc882c](fdc882cb04))
* update locked room terminology and allow existing members ([1ddf985](1ddf985938))
* use app-wide abacus config and remove instruction text ([0a50c73](0a50c733b0))
* use color instead of fill for numeral styling ([ea10c16](ea10c16811))
* use defaultValue for interactive abacus control ([06aca98](06aca986ac))
* use useCreateRoom hook instead of nonexistent createRoom from useRoomData ([f7d63b3](f7d63b30ac))

### Code Refactoring

* **db:** remove database schema coupling for game names ([e135d92](e135d92abb)), closes [#1](https://github.com/antialias/soroban-abacus-flashcards/issues/1)

### Features

* **abacus-react:** add BigInt support for 30-digit Dan level abacuses ([0ab4cc2](0ab4cc2880))
* add API routes for moderation and invitations ([79a8518](79a8518557))
* add backend library functions for room moderation ([84f3c4b](84f3c4bcfd))
* add common UI components ([cd3115a](cd3115aa6d))
* add database schema for room moderation and invitations ([97d1604](97d16041df))
* add drizzle migration for room_game_configs table ([3bae00b](3bae00b9a9))
* add fun automatic player naming system ([249257c](249257c6c7))
* add invitation system UI components ([fd3a2d1](fd3a2d1f76))
* add moderation panel with unban & invite feature ([a2d0169](a2d0169f80))
* add name generator button and abacus emoji ([07212e4](07212e4df0))
* add player count to stacked room info ([540f6b7](540f6b76d0))
* add prominent join request approval notifications for room moderators ([036da6d](036da6de66))
* add real-time socket updates for moderation events ([86ceba3](86ceba3df3))
* add room access modes and ownership transfer ([6ff21c4](6ff21c4f1d))
* add room creation and join flow UI ([7f95032](7f95032253))
* add socket listener and polling for approval notifications ([35b4a72](35b4a72c8b))
* add waiting state for approval requests in JoinRoomModal ([f9b0429](f9b0429a2e))
* adjust tier probabilities for more abacus flavor ([49219e3](49219e34cd))
* **arcade:** add Card Sorting Challenge game scaffolding ([df37260](df37260e26))
* **arcade:** add Change Game functionality for room hosts ([ee39241](ee39241e3c))
* **arcade:** add game selection screen with navigation to room page ([4124f1c](4124f1cc08))
* **arcade:** add Math Sprint game implementation ([e5be09e](e5be09ef5f))
* **arcade:** add modular game SDK and registry system ([de30bec](de30bec479))
* **arcade:** add Number Guesser demo game with plugin architecture ([0e3c058](0e3c058707))
* **arcade:** broadcast game selection changes to all room members ([b99e754](b99e754395))
* **arcade:** migrate matching pairs - phases 1-4 and 7 complete ([2a3af97](2a3af973f7))
* **arcade:** migrate memory-quiz to modular game system ([f48c37a](f48c37accc))
* **arcade:** register Math Sprint in game system ([0c05a7c](0c05a7c6bb)), closes [#2](https://github.com/antialias/soroban-abacus-flashcards/issues/2) [#3](https://github.com/antialias/soroban-abacus-flashcards/issues/3)
* **card-sorting:** add spectator mode UX enhancements ([4ab093a](4ab093a9d8))
* **card-sorting:** add UI components and fix AbacusReact props ([d249ec0](d249ec0e5f))
* **card-sorting:** implement Provider with arcade session integration ([7f6fea9](7f6fea91f6))
* **complement-race:** add infinite win condition for Steam Sprint mode ([d8fdfee](d8fdfeef74))
* **complement-race:** add mini app navigation bar ([ed0ef2d](ed0ef2d3b8))
* **complement-race:** enable adaptive AI difficulty in arcade ([55010d2](55010d2bcd))
* **complement-race:** implement state adapter for multiplayer support ([13882bd](13882bda32))
* **complement-race:** restore AI opponents in practice and survival modes ([325e07d](325e07de59))
* **homepage:** add animated mini abacus to "Read and set numbers" card ([e028e34](e028e342ad))
* **homepage:** add more visual embellishments to learning cards ([4ec1b95](4ec1b952f2))
* **homepage:** enhance "What You'll Learn" with visual cards ([d142342](d1423420e6))
* **home:** redesign home page to showcase complete platform ([ee6c4f2](ee6c4f2f4f))
* implement approval request flow for share links ([4a6b3ca](4a6b3cabe5))
* implement avatar-themed name generation with probabilistic mixing ([76a8472](76a8472f12))
* implement proper retired room behavior with member expulsion ([a2d5368](a2d53680f2))
* improve arcade nav player grouping and add room join code display ([8e9980d](8e9980dc82))
* improve room creation UX and add password support for share links ([dcbb507](dcbb5072d8))
* integrate moderation system into arcade pages ([087652f](087652f9e7))
* **levels:** add Dan levels ladder visualization ([c18012c](c18012cb50))
* **levels:** add dark mode styling and responsive scaling to abacus ([92e1e62](92e1e62132))
* **levels:** add informational footer section ([0b1bff7](0b1bff7eab))
* **levels:** add Kyu & Dan levels page with homepage link ([39b1e7d](39b1e7de16))
* **levels:** add kyu level data and cards ([6463a3b](6463a3b2f6))
* **levels:** create true horizontal slider with abacus visualizations ([6d734f1](6d734f1d51))
* **levels:** implement interactive slider for exploring kyu & dan ranks ([eb3b100](eb3b100056))
* **levels:** replace kyu grid with interactive slider and abacus visualizations ([10978e8](10978e890b))
* make home page abacus interactive with audio ([9a53d7e](9a53d7e5db))
* **matching:** use nav avatars as turn indicators ([7263828](7263828ed4))
* **math-sprint:** add game manifest ([1eefcc8](1eefcc89a5))
* **memory-quiz:** add multiplayer support with redesigned scoreboards ([1cf4469](1cf44696c2))
* **memory-quiz:** persist game settings per-game across sessions ([05a8e0a](05a8e0a842))
* **memory-quiz:** show player emojis on cards to indicate who found them ([05bd11a](05bd11a133))
* **moderation:** add inline feedback and persistent password display ([86e3d41](86e3d41996))
* **moderation:** improve password input with copy button ([2580e47](2580e474d0))
* **nav:** add prominent turn indicator arrow badge ([f574558](f574558dff))
* **nav:** add pulsing indicator for offline network players ([64fb30e](64fb30e7ec))
* **nav:** add turn indicators to network players ([623314b](623314bd38))
* **nav:** add turn label text under current player avatars ([52a66d5](52a66d5f68))
* **nav:** center game context with hamburger menu for utilities ([a35a7d5](a35a7d56df))
* **nav:** combine room info and network players in single pane ([d5473ab](d5473ab66a))
* **nav:** unify room dropdown with join code and game menu ([f7b83f8](f7b83f8c14))
* prevent invitations to retired rooms ([a7c3c1f](a7c3c1f4cd))
* redesign home page with component showcase ([29af265](29af265958))
* redesign homepage with educational vision and interactive demo ([2f09cb5](2f09cb5539))
* redesign room info as compact inline badge with click-to-copy ([6b3a440](6b3a440369))
* replace access mode dropdown with visual button grid ([e5d0672](e5d0672059))
* **tutorial:** add dark mode styling for coaching bar and abacus frame ([7e2f580](7e2f580877))
* **tutorial:** add dark theme and column control props ([d42f9b2](d42f9b2d9a))
* **tutorial:** add fill color support for dark mode column posts and reckoning bar ([2eb3ff3](2eb3ff3406))
* **tutorial:** add hideNavigation prop to TutorialPlayer ([79ea52a](79ea52af80))
* **tutorial:** add hideTooltip prop and improve dark mode coaching bar ([1ee25b3](1ee25b3dd2))
* **tutorial:** add silentErrors prop to suppress error messages ([8835e1c](8835e1c57a))

### Reverts

* **nav:** restore original room creation/join behavior ([710e93c](710e93c997))

### BREAKING CHANGES

* **db:** Database schemas now accept any string for game names
* Added DELETE /api/arcade/rooms/:roomId/invite endpoint for declining invitations

Authorization Error Handling:
- ModerationPanel: Parse and display API error messages (kick, ban, unban, invite, data loading)
- PendingInvitations: Parse and display API error messages (decline, fetch)
- All moderation actions now show specific auth errors like "Only the host can kick users"

New Endpoint:
- DELETE /api/arcade/rooms/:roomId/invite: Allow users to decline their pending invitations
  * Validates invitation exists and is pending
  * Only invited user can decline their own invitation
  * Returns proper error messages for auth failures

Bug Fix:
- Fixed invitations/pending/route.ts ban check query (removed reference to non-existent unbannedAt field)
- Ban records are deleted when unbanned, so any existing ban is active

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 13:34:47 +00:00
Thomas Hallock
0ab4cc2880 feat(abacus-react): add BigInt support for 30-digit Dan level abacuses
Add BigInt support to AbacusReact to handle 30-digit numbers without
precision loss (JavaScript's Number.MAX_SAFE_INTEGER is ~16 digits).

Changes:
- Update AbacusReact types to accept `value?: number | bigint`
- Modify useAbacusPlaceStates hook to use string-based digit parsing
- Add conditional BigInt arithmetic for >15 digits (maxPlaceValue > 14)
- Update levels page to pass BigInt for Dan levels (30 columns)
- Fix games page Date comparison (unrelated TypeScript error)

The implementation automatically detects when BigInt is needed based on
the number of digits, maintaining backward compatibility.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 08:33:31 -05:00
semantic-release-bot
6b7c455315 chore(release): 4.32.1 [skip ci]
## [4.32.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.32.0...v4.32.1) (2025-10-20)

### Bug Fixes

* **levels:** use correct dark mode styling from homepage + docs update ([c38767f](c38767f4d3))
2025-10-20 13:00:25 +00:00
Thomas Hallock
c38767f4d3 fix(levels): use correct dark mode styling from homepage + docs update
Fixed abacus styling issues by matching homepage implementation:
- Use `fill` (not just `stroke`) for columnPosts and reckoningBar
- Changed from all zeros to interesting display value (123456...)
- Removed incorrect color customization causing mixed bead styles
- Now uses exact same darkStyles pattern as homepage MiniAbacus

Documentation update:
- Added MANDATORY section: "Read the Docs Before Customizing"
- Emphasized always reading packages/abacus-react/README.md
- Added references to homepage and storybook examples
- Included concrete example of correct darkStyles usage
- Key point: columnPosts and reckoningBar need `fill` property

This ensures columns and reckoning bar are now visible on dark backgrounds
and provides guidance to prevent similar issues in the future.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 07:59:08 -05:00
semantic-release-bot
321d9aea10 chore(release): 4.32.0 [skip ci]
## [4.32.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.31.1...v4.32.0) (2025-10-20)

### Features

* **levels:** add dark mode styling and responsive scaling to abacus ([92e1e62](92e1e62132))
2025-10-20 12:50:34 +00:00
Thomas Hallock
92e1e62132 feat(levels): add dark mode styling and responsive scaling to abacus
Improvements to the levels page abacus display:
- Added showNumbers={true} to show place value numbers
- Styled for dark background with light gray columns and reckoning bar
- Colored beads (blue heaven, green earth) for better visibility
- Dynamic scaling: large (2.5x) for Kyu levels, smaller for Dan levels
- Added horizontal overflow for very wide Dan level abacuses (30 columns)
- Formula: scaleFactor = Math.min(2.5, 20 / digits)

The abacus now fits gracefully at all levels and is clearly visible
on the dark page background.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 07:49:28 -05:00
semantic-release-bot
84d980bb24 chore(release): 4.31.1 [skip ci]
## [4.31.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.31.0...v4.31.1) (2025-10-20)

### Bug Fixes

* **levels:** use correct AbacusReact API with direct props ([892b377](892b377eb3))
2025-10-20 12:47:01 +00:00
Thomas Hallock
892b377eb3 fix(levels): use correct AbacusReact API with direct props
Fixed abacus not rendering by using the correct API:
- Removed non-existent useAbacusConfig import
- Changed from config object to direct props (value, columns, scaleFactor)
- Added scaleFactor=1.5 for better visibility

The abacus now properly displays with the appropriate number of columns
based on the selected kyu/dan level.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 07:45:53 -05:00
semantic-release-bot
bc21095fa1 chore(release): 4.31.0 [skip ci]
## [4.31.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.30.0...v4.31.0) (2025-10-20)

### Features

* **levels:** implement interactive slider for exploring kyu & dan ranks ([eb3b100](eb3b100056))
2025-10-20 12:41:45 +00:00
Thomas Hallock
eb3b100056 feat(levels): implement interactive slider for exploring kyu & dan ranks
Replace static grid layout with an interactive range slider that allows
users to explore all 21 kyu and dan levels dynamically. The slider updates
a single AbacusReact component showing the appropriate number of columns
(2-30 digits) based on the selected rank.

Features:
- HTML range input slider from 10th Kyu to 10th Dan
- Dynamic abacus visualization using @soroban/abacus-react
- Real-time updates of level metadata (emoji, name, min score)
- Color-coded borders matching progression levels
- Reference markers for key ranks

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 07:40:19 -05:00
semantic-release-bot
276f6f0744 chore(release): 4.30.0 [skip ci]
## [4.30.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.29.0...v4.30.0) (2025-10-20)

### Features

* **levels:** create true horizontal slider with abacus visualizations ([6d734f1](6d734f1d51))
2025-10-20 12:34:34 +00:00
Thomas Hallock
6d734f1d51 feat(levels): create true horizontal slider with abacus visualizations
Replace carousel with actual horizontal slider showing all 21 ranks:
- Continuous scrollable view of 10 Kyu levels + 11 Dan levels
- Each level card displays:
  - Level name, emoji, and metadata
  - Visual abacus showing digit mastery (2-30 columns)
  - Color-coded by progression (green→blue→violet→amber)
- Simplified abacus columns with proper visual structure
- Visual transition marker between Kyu and Dan sections
- Color legend for all four progression stages
- Fully mobile-responsive horizontal scrolling

Also add documentation note about using @soroban/abacus-react for all
abacus visualizations in the codebase.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 07:33:36 -05:00
semantic-release-bot
03b9b1228b chore(release): 4.29.0 [skip ci]
## [4.29.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.28.0...v4.29.0) (2025-10-20)

### Features

* **levels:** replace kyu grid with interactive slider and abacus visualizations ([10978e8](10978e890b))
2025-10-20 12:30:16 +00:00
Thomas Hallock
10978e890b feat(levels): replace kyu grid with interactive slider and abacus visualizations
Replace cluttered static grid of kyu level cards with an elegant horizontal slider.
Each level now features:
- Interactive slider with left/right navigation buttons
- Keyboard navigation support (arrow keys)
- Visual abacus showing digit mastery progression (2-10 columns)
- Clickable progress indicators
- Smooth transitions and hover effects
- Mobile-responsive design

The abacus visualizations provide an intuitive representation of the student's
progression through each level, showing the increasing number of digit columns
they master from 10th Kyu (2 digits) to 1st Kyu (10 digits).

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 07:29:11 -05:00
semantic-release-bot
6d86281c63 chore(release): 4.28.0 [skip ci]
## [4.28.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.27.0...v4.28.0) (2025-10-20)

### Features

* **levels:** add informational footer section ([0b1bff7](0b1bff7eab))
2025-10-20 12:24:15 +00:00
Thomas Hallock
0b1bff7eab feat(levels): add informational footer section
Add comprehensive "About This Ranking System" section at the bottom of the
page explaining the Japan Abacus Federation ranking system and its purpose.

Features:
- Educational context about the JAF ranking system
- Explanation of progressive difficulty structure
- Clear disclaimer about educational vs certification purposes
- Professional styling matching the rest of the page
- Mobile-responsive padding and typography

Phase 6 complete: Final polish with educational context and disclaimers.

All phases complete! The /levels page now provides:
- Complete kyu level information (10th to 1st)
- Dan level ladder visualization (Pre-1st Dan to 10th Dan)
- Exam requirements and scoring details
- Educational context and disclaimers

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 07:23:10 -05:00
semantic-release-bot
f70ded30b9 chore(release): 4.27.0 [skip ci]
## [4.27.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.26.0...v4.27.0) (2025-10-20)

### Features

* **levels:** add Dan levels ladder visualization ([c18012c](c18012cb50))
2025-10-20 12:18:57 +00:00
Thomas Hallock
c18012cb50 feat(levels): add Dan levels ladder visualization
Add comprehensive Dan level section (Pre-1st Dan to 10th Dan) with score-based
ranking system. Display as vertical ladder showing progression from 90 to 290
points.

Features:
- Dan exam requirements box (30-digit problems, 3× 1st Kyu complexity)
- Ladder visualization with 11 Dan ranks
- Japanese names (Shodan, Nidan, etc.)
- Score thresholds for each rank
- Amber/gold color theme for master ranks
- Hover effects on each ladder rung
- Mobile-responsive design

Phase 4 complete: Full Dan ranking system with official JAF requirements.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 07:17:51 -05:00
semantic-release-bot
25a3356547 chore(release): 4.26.0 [skip ci]
## [4.26.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.25.1...v4.26.0) (2025-10-20)

### Features

* **levels:** add kyu level data and cards ([6463a3b](6463a3b2f6))
2025-10-20 12:15:15 +00:00
Thomas Hallock
6463a3b2f6 feat(levels): add kyu level data and cards
Add comprehensive kyu level information from 10th to 1st Kyu with detailed
exam requirements. Display data in responsive grid of color-coded cards.

Data includes:
- Duration, pass thresholds, and point requirements
- Problem types with digit complexity for each operation
- Color-coded by difficulty (green → blue → violet)
- Hover effects and mobile-responsive layout

Phase 2 complete: All 10 kyu levels with official JAF requirements.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 07:14:16 -05:00
semantic-release-bot
7f6c486e9c chore(release): 4.25.1 [skip ci]
## [4.25.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.25.0...v4.25.1) (2025-10-20)

### Code Refactoring

* **homepage:** make entire "Your Journey" card clickable ([3f30810](3f30810271))
2025-10-20 12:08:33 +00:00
Thomas Hallock
3f30810271 refactor(homepage): make entire "Your Journey" card clickable
Transform the journey section into an interactive card that navigates to
/levels. Remove separate button in favor of whole-card clickability with
clear hover feedback.

Changes:
- Wrap entire card in Link component
- Add hover effects: lift, violet border, purple shadow
- Add subtle arrow indicator in top-right corner
- Update text: "Click to learn about the official Japanese ranking system"

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 07:07:34 -05:00
semantic-release-bot
4968e2c846 chore(release): 4.25.0 [skip ci]
## [4.25.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.24.3...v4.25.0) (2025-10-20)

### Features

* **levels:** add Kyu & Dan levels page with homepage link ([39b1e7d](39b1e7de16))

### Styles

* **homepage:** adjust journey emoji sizing and spacing ([2a0e469](2a0e469e83))
2025-10-20 11:51:46 +00:00
Thomas Hallock
39b1e7de16 feat(levels): add Kyu & Dan levels page with homepage link
Create new /levels page with hero section explaining the Japanese soroban
ranking system (10th Kyu to 10th Dan). Add navigation link from homepage
"Your Journey" section with violet-themed button styling.

Phase 1 complete: basic page structure and routing ready for content.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 06:50:35 -05:00
Thomas Hallock
2a0e469e83 style(homepage): adjust journey emoji sizing and spacing
Increase emoji size from 3xl to 5xl for better visual presence.
Tighten spacing between emojis and labels by setting gap to 0 and
adding negative top margin (-2) to level labels.

Changes:
- Increase emoji fontSize from '3xl' to '5xl'
- Remove emoji bottom margin (mb: '0')
- Remove gap between emoji and labels (gap: '0')
- Add negative top margin to level labels (mt: '-2')

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 06:37:59 -05:00
semantic-release-bot
b3541e6b8a chore(release): 4.24.3 [skip ci]
## [4.24.3](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.24.2...v4.24.3) (2025-10-20)

### Code Refactoring

* **homepage:** align all skill icon panes horizontally ([4b04e86](4b04e8673d))
2025-10-20 11:22:23 +00:00
Thomas Hallock
4b04e8673d refactor(homepage): align all skill icon panes horizontally
Removed horizontal padding for all skill icon containers to ensure
consistent alignment across the "What You'll Learn" section.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 06:21:25 -05:00
semantic-release-bot
75a84dc148 chore(release): 4.24.2 [skip ci]
## [4.24.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.24.1...v4.24.2) (2025-10-20)

### Code Refactoring

* **homepage:** tighten mini abacus vertical padding ([514d07e](514d07ecb5))
2025-10-20 11:17:40 +00:00
Thomas Hallock
514d07ecb5 refactor(homepage): tighten mini abacus vertical padding
Reduced vertical padding from token '5' to '4' in the "Read and set
numbers" card icon container for better visual balance.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 06:16:37 -05:00
semantic-release-bot
e37ee87ea3 chore(release): 4.24.1 [skip ci]
## [4.24.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.24.0...v4.24.1) (2025-10-20)

### Bug Fixes

* **homepage:** adjust mini abacus container height ([c4066d6](c4066d6879))
* **homepage:** fix MiniAbacus runtime error and improve sizing ([1fa0df8](1fa0df85f7))
* **homepage:** use correct AbacusReact API and fix clipping/styling issues ([1432afd](1432afd6e6))
* **homepage:** use direct conditionals for mini abacus padding ([38ef16a](38ef16a8f9))

### Styles

* **homepage:** add more padding around mini abacus ([c5103d0](c5103d049f))
* **homepage:** balance mini abacus padding horizontally and vertically ([2f0304e](2f0304eb81))
* **homepage:** increase mini abacus padding to '5' ([1da9ed1](1da9ed1ce6))
2025-10-20 11:11:51 +00:00
Thomas Hallock
38ef16a8f9 fix(homepage): use direct conditionals for mini abacus padding
Replace spread operator with direct conditional values for py and px
to ensure proper application with Panda CSS.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 06:10:44 -05:00
Thomas Hallock
2f0304eb81 style(homepage): balance mini abacus padding horizontally and vertically
Use py: '5' and px: '3' instead of uniform padding to create visually
equal spacing on all sides of the animated abacus.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 06:09:49 -05:00
Thomas Hallock
1da9ed1ce6 style(homepage): increase mini abacus padding to '5'
Double the padding from '3' to '5' for more generous vertical spacing
around the animated abacus.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 06:09:13 -05:00
Thomas Hallock
c5103d049f style(homepage): add more padding around mini abacus
Increase padding from '2' to '3' on the mini abacus icon container
to provide more vertical space between the abacus and the card border.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 06:08:52 -05:00
Thomas Hallock
c4066d6879 fix(homepage): adjust mini abacus container height
Set container height to 80px to prevent excess vertical space while
keeping the abacus fully visible and centered.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 06:07:41 -05:00
Thomas Hallock
1432afd6e6 fix(homepage): use correct AbacusReact API and fix clipping/styling issues
Use the correct pattern for AbacusReact:
- Call useAbacusConfig() without parameters for global config
- Pass individual props (value, columns, beadShape, styles) instead of config object
- No more timing hacks - the proper API doesn't have initialization issues

Fix display issues:
- Remove fixed height and overflow:hidden to prevent clipping
- Add dark theme styles for columnPosts and reckoningBar
- Reduce scale from 0.7 to 0.6 with proper transform origin

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 06:06:42 -05:00
Thomas Hallock
1fa0df85f7 fix(homepage): fix MiniAbacus runtime error and improve sizing
Fix "Cannot read properties of undefined (reading 'earthActive')" error by:
- Adding 500ms initialization delay before starting value cycling
- Starting with value 123 instead of 0 to show valid state immediately
- Splitting ready state management into separate useEffect

Also improve container sizing:
- Set explicit width (75px) and height (75px)
- Add transform scale(0.7) to fit better in card icon space
- Add overflow hidden to contain the component
- Increase cycle interval to 2.5s for smoother transitions

The error occurred because the AbacusReact component was trying to access
column states before they were fully initialized. The delay ensures proper
initialization before animation starts.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 06:06:42 -05:00
semantic-release-bot
8baeba6987 chore(release): 4.24.0 [skip ci]
## [4.24.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.23.0...v4.24.0) (2025-10-20)

### Features

* **homepage:** add animated mini abacus to "Read and set numbers" card ([e028e34](e028e342ad))
2025-10-20 11:01:48 +00:00
Thomas Hallock
e028e342ad feat(homepage): add animated mini abacus to "Read and set numbers" card
Replace static 🔢 emoji with a functional 3-column abacus that cycles through
random 3-digit numbers (0-999) every 2 seconds. Uses dark theme styling to
match the homepage aesthetic.

Changes:
- Create MiniAbacus component using AbacusReact
- Cycle through random numbers using useState/useEffect
- Constrain height to ~75px as specified
- Conditionally render in first skill card (i === 0)
- Use theme="dark" to match tutorial abacus styling

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 06:00:46 -05:00
semantic-release-bot
263237a152 chore(release): 4.23.0 [skip ci]
## [4.23.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.22.0...v4.23.0) (2025-10-20)

### Features

* **homepage:** add more visual embellishments to learning cards ([4ec1b95](4ec1b952f2))
2025-10-20 10:57:15 +00:00
Thomas Hallock
4ec1b952f2 feat(homepage): add more visual embellishments to learning cards
Significantly enhance "What You'll Learn" section with:
- Larger icons (3xl) with background containers
- Skill level badges (Foundation/Core/Advanced/Expert)
- More padding and spacing throughout
- Gradient backgrounds on cards
- Box shadows with depth
- Hover lift animations
- Longer, more detailed descriptions
- Example text styled as highlighted code badges
- Increased container width for better balance

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 05:56:02 -05:00
semantic-release-bot
aa9d389540 chore(release): 4.22.0 [skip ci]
## [4.22.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.21.1...v4.22.0) (2025-10-20)

### Features

* **homepage:** enhance "What You'll Learn" with visual cards ([d142342](d1423420e6))

### Bug Fixes

* **tutorial:** reduce tooltip z-index to scroll under nav bar ([47640f3](47640f3486))
2025-10-20 10:55:50 +00:00
Thomas Hallock
d1423420e6 feat(homepage): enhance "What You'll Learn" with visual cards
Replace simple checklist with rich visual cards for each learning objective.
Each card now includes:
- Large prominent icon
- Title and description
- Example/demo text
- Hover effects
- Card-based layout with subtle borders

Makes the section more engaging and less text-heavy, better balanced with
the tutorial demo on the left.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 05:54:44 -05:00
Thomas Hallock
47640f3486 fix(tutorial): reduce tooltip z-index to scroll under nav bar
Change tutorial tooltip z-index from 1000 to 50 so it scrolls under the
app nav bar (z-index 100) along with the abacus. This prevents the coaching
text from appearing layered above the nav while the abacus it points to is
hidden beneath it.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 05:54:44 -05:00
semantic-release-bot
cb7595c95b chore(release): 4.21.1 [skip ci]
## [4.21.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.21.0...v4.21.1) (2025-10-20)

### Code Refactoring

* **homepage:** rearrange tutorial demo layout side by side ([8b4ecee](8b4eceebfa))
2025-10-20 10:52:32 +00:00
Thomas Hallock
8b4eceebfa refactor(homepage): rearrange tutorial demo layout side by side
Restructure "Learn by Doing" section to display tutorial and "What You'll
Learn" side by side. Items now display vertically instead of in a 2x2 grid.

Changes:
- Tutorial positioned on left with flex: 1
- "What You'll Learn" section positioned on right
- Items arranged vertically using stack layout
- Increased container max-width from 900px to 1200px
- Responsive: stacks vertically on mobile, side-by-side on md+ screens

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 05:51:29 -05:00
semantic-release-bot
850fd33943 chore(release): 4.21.0 [skip ci]
## [4.21.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.20.7...v4.21.0) (2025-10-20)

### Features

* **tutorial:** add silentErrors prop to suppress error messages ([8835e1c](8835e1c57a))
2025-10-20 10:50:59 +00:00
Thomas Hallock
8835e1c57a feat(tutorial): add silentErrors prop to suppress error messages
Add silentErrors prop to TutorialPlayer to allow suppressing "That's not
the highlighted bead" error messages. Used on homepage to provide a less
intrusive demo experience.

Changes:
- Add silentErrors prop to TutorialPlayerProps interface
- Conditionally skip error dispatch when silentErrors is true
- Pass silentErrors={true} from homepage TutorialPlayer

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 05:49:43 -05:00
Thomas Hallock
b635ed1c2d chore(home): reduce abacus tutorial to single column
Changed abacusColumns from 2 to 1 for the homepage tutorial demo.
Since the "Friends of 5" (2+3) demonstration only needs the ones place,
a single column is more focused and less distracting.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 05:44:24 -05:00
semantic-release-bot
4e6cecfe27 chore(release): 4.20.7 [skip ci]
## [4.20.7](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.20.6...v4.20.7) (2025-10-20)

### Bug Fixes

* **home:** use Panda CSS token() for dynamic colors and center arrows properly ([d52ba63](d52ba6373a))
2025-10-20 02:37:39 +00:00
Thomas Hallock
d52ba6373a fix(home): use Panda CSS token() for dynamic colors and center arrows properly
**Changes:**
- Use Panda CSS token() function for dynamic color references instead of inline hex values
- Fix arrow positioning to be centered in gap between progression stages
- Document Panda CSS dynamic token usage pattern

**Color Token Fix:**
Panda CSS css() requires static values at build time. For dynamic token references,
use the token() function with inline styles:
- Import: token from styled-system/tokens
- Usage: style={{ color: token(stage.color) }}
- Token paths marked as const for TypeScript literal types

**Arrow Positioning Fix:**
Arrows between stages were positioned based on element width, not gap width.
Now properly centered using:
- left: 100% (position at right edge)
- marginLeft: 0.5rem (half of 1rem gap)
- transform: translate(-50%, -50%) (center on that point)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-19 21:36:30 -05:00
semantic-release-bot
002c2888ac chore(release): 4.20.6 [skip ci]
## [4.20.6](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.20.5...v4.20.6) (2025-10-20)

### Bug Fixes

* **homepage:** use inline styles for journey level colors ([5d85e89](5d85e898d6)), closes [#4ade80](https://github.com/antialias/soroban-abacus-flashcards/issues/4ade80) [#60a5](https://github.com/antialias/soroban-abacus-flashcards/issues/60a5) [#a78](https://github.com/antialias/soroban-abacus-flashcards/issues/a78) [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24)
2025-10-20 01:14:49 +00:00
Thomas Hallock
5d85e898d6 fix(homepage): use inline styles for journey level colors
Changed progression level text from Panda CSS tokens to inline hex colors:
- 10 Kyu: #4ade80 (green)
- 5 Kyu: #60a5fa (blue)
- 1 Kyu: #a78bfa (purple)
- Dan: #fbbf24 (gold)

This ensures all text displays with proper colors regardless of CSS loading.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-19 20:13:39 -05:00
semantic-release-bot
eed890dc81 chore(release): 4.20.5 [skip ci]
## [4.20.5](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.20.4...v4.20.5) (2025-10-20)

### Bug Fixes

* **docker:** include Panda CSS styled-system in production image ([57fabff](57fabffe60))
2025-10-20 01:12:42 +00:00
Thomas Hallock
57fabffe60 fix(docker): include Panda CSS styled-system in production image
The styled-system directory containing generated Panda CSS was being
created during build but not copied to the production image, causing
all Panda CSS classes to be undefined at runtime.

This fix copies the generated styled-system directory from the builder
stage to the production image, ensuring styles.css is available.

Fixes missing CSS definitions for classes like fs_xl, font_bold, text_blue.400

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-19 20:11:38 -05:00
semantic-release-bot
89fb670f93 chore(release): 4.20.4 [skip ci]
## [4.20.4](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.20.3...v4.20.4) (2025-10-19)

### Bug Fixes

* **homepage:** use inline styles for Your Journey text contrast ([8e51390](8e51390018)), closes [#e5e7](https://github.com/antialias/soroban-abacus-flashcards/issues/e5e7) [#e5e7](https://github.com/antialias/soroban-abacus-flashcards/issues/e5e7) [#9ca3](https://github.com/antialias/soroban-abacus-flashcards/issues/9ca3) [#d1d5](https://github.com/antialias/soroban-abacus-flashcards/issues/d1d5)
2025-10-19 19:07:08 +00:00
Thomas Hallock
8e51390018 fix(homepage): use inline styles for Your Journey text contrast
Switched from Panda CSS to direct inline styles with hex colors:
- Labels (Beginner/Intermediate/Advanced/Master): #e5e7eb (light gray)
- Subtitle: #e5e7eb (light gray)
- Arrows: #9ca3af (medium gray)
- Footer: #d1d5db (light gray)

This bypasses any CSS framework issues and applies colors directly.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-19 14:06:02 -05:00
semantic-release-bot
e7e54619ae chore(release): 4.20.3 [skip ci]
## [4.20.3](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.20.2...v4.20.3) (2025-10-19)

### Bug Fixes

* **homepage:** use explicit RGBA colors for Your Journey text ([9c51cc9](9c51cc94ee))
2025-10-19 18:58:39 +00:00
Thomas Hallock
9c51cc94ee fix(homepage): use explicit RGBA colors for Your Journey text
Switched from Panda CSS gray tokens to explicit RGBA values for better compatibility:
- Text: rgba(229, 231, 235, 1) - light gray for maximum readability
- Subtitle: rgba(209, 213, 219, 1) - slightly darker light gray
- Arrows: rgba(156, 163, 175, 1) - medium gray

This ensures proper rendering regardless of theme token configuration.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-19 13:57:30 -05:00
18 changed files with 3437 additions and 534 deletions

View File

@@ -1,3 +1,516 @@
## [4.48.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.48.1...v4.48.2) (2025-10-20)
### Bug Fixes
* **nav:** ensure nav bar appears above tutorial tooltips ([cc31564](https://github.com/antialias/soroban-abacus-flashcards/commit/cc315645de30218d1b034da3e130458fe2961a69))
### Styles
* **hero:** unify background with rest of homepage ([035d831](https://github.com/antialias/soroban-abacus-flashcards/commit/035d8312c707cbf5b0e2a725d7b1d8ff406f842d))
## [4.48.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.48.0...v4.48.1) (2025-10-20)
### Bug Fixes
* **hero:** prevent SSR hydration mismatch for subtitle ([1bfde8f](https://github.com/antialias/soroban-abacus-flashcards/commit/1bfde8fb251b227ccd2528bfe1c47acffd79fa49))
## [4.48.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.47.2...v4.48.0) (2025-10-20)
### Features
* **hero:** persist random subtitle per-session ([318f946](https://github.com/antialias/soroban-abacus-flashcards/commit/318f9469a0805c200c55ce4024a95fd7b8dbe6a2))
## [4.47.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.47.1...v4.47.2) (2025-10-20)
### Bug Fixes
* **nav:** prevent thrashing by using fixed position always ([eff44b3](https://github.com/antialias/soroban-abacus-flashcards/commit/eff44b3ad1ea0535c6965ad58012f9275cb143ec))
* **nav:** remove unnecessary borders from transparent nav ([8c2ddca](https://github.com/antialias/soroban-abacus-flashcards/commit/8c2ddca28dbdd7743227eed4d19a9a8f662a72b5))
## [4.47.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.47.0...v4.47.1) (2025-10-20)
### Bug Fixes
* **hero:** prevent nav thrashing with hysteresis ([71b1b93](https://github.com/antialias/soroban-abacus-flashcards/commit/71b1b933b598c0a6a8aef1bc9f8c598c1871b2eb))
## [4.47.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.46.2...v4.47.0) (2025-10-20)
### Features
* **nav:** add transparent nav bar with borders when hero visible ([463841e](https://github.com/antialias/soroban-abacus-flashcards/commit/463841e1910f4ddb9af662f036e4efb867836a83))
### Bug Fixes
* **hero:** use Number.isNaN instead of global isNaN ([c229faf](https://github.com/antialias/soroban-abacus-flashcards/commit/c229faffac525f3eebeb12155cb5ca4dff744472))
### Styles
* **hero-abacus:** add purple bead colors for dark theme ([721dfe4](https://github.com/antialias/soroban-abacus-flashcards/commit/721dfe426db4fe259f6cdeac587d008339df769b))
* **hero:** adjust spacing between title, subtitle, and abacus ([3a3706c](https://github.com/antialias/soroban-abacus-flashcards/commit/3a3706cc6fb694c7762f065f4ab4996bb8608dc4))
## [4.46.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.46.1...v4.46.2) (2025-10-20)
### Bug Fixes
* **types:** properly type HomeHeroContext in AppNavBar ([f9a7cb7](https://github.com/antialias/soroban-abacus-flashcards/commit/f9a7cb7f05dfddf291d89212a77ba1c11c00c9c7))
## [4.46.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.46.0...v4.46.1) (2025-10-20)
### Bug Fixes
* **hero-abacus:** restructure layout to prevent visual overlap ([02b6c70](https://github.com/antialias/soroban-abacus-flashcards/commit/02b6c70b7a52f7de2954e5e0efddbed64d419d6c))
## [4.46.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.45.0...v4.46.0) (2025-10-20)
### Features
* **homepage:** add full-page hero abacus with scroll-based nav transition ([d8ec642](https://github.com/antialias/soroban-abacus-flashcards/commit/d8ec64280ec0c2f44f2fd9c72a93a882481f650b))
### Bug Fixes
* **homepage:** improve hero abacus sizing and layout ([230f1dc](https://github.com/antialias/soroban-abacus-flashcards/commit/230f1dcd866e5b3625e19f7400f5eae478fe7d0c))
### Styles
* **hero-abacus:** apply dark theme to match homepage styling ([e0b6a2e](https://github.com/antialias/soroban-abacus-flashcards/commit/e0b6a2e88b3ebbaae41ed54f23f9e514604d2262))
## [4.45.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.44.3...v4.45.0) (2025-10-20)
### Features
* **branding:** rebrand navigation from 'Soroban Generator' to 'Abaci One' ([cce8980](https://github.com/antialias/soroban-abacus-flashcards/commit/cce8980e177da1b3c344e46561d928ed98b86f6c))
## [4.44.3](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.44.2...v4.44.3) (2025-10-20)
### Bug Fixes
* **levels:** reduce operator box sizes and remove divider line ([29d20a6](https://github.com/antialias/soroban-abacus-flashcards/commit/29d20a6c0741e7427f2bb64bc9c3e950b1a3238a))
* **levels:** use uniform padding on operator box grid ([2818fd1](https://github.com/antialias/soroban-abacus-flashcards/commit/2818fd15cacac78de6d86ba769b9b2a02800ed1e))
## [4.44.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.44.1...v4.44.2) (2025-10-20)
### Bug Fixes
* **levels:** match top/bottom margins to left padding on kyu detail boxes ([aa0bdcf](https://github.com/antialias/soroban-abacus-flashcards/commit/aa0bdcf686adcbfd1a145cf67121181d1f1194d9))
## [4.44.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.44.0...v4.44.1) (2025-10-20)
### Bug Fixes
* **levels:** add fixed dimensions and margins to kyu detail boxes ([05dd0b3](https://github.com/antialias/soroban-abacus-flashcards/commit/05dd0b30d3c397b82b7b7cc93a5ea575f3aada6d))
## [4.44.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.43.2...v4.44.0) (2025-10-20)
### Features
* **levels:** redesign kyu details with larger operators and prominent digits ([6739d59](https://github.com/antialias/soroban-abacus-flashcards/commit/6739d59f2b6189a98570e23e04c20d86d774ccce))
## [4.43.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.43.1...v4.43.2) (2025-10-20)
### Code Refactoring
* **levels:** remove Time and Pass sections from kyu details ([d90b5d5](https://github.com/antialias/soroban-abacus-flashcards/commit/d90b5d55322e75dd28b95376614663a506c829d4))
## [4.43.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.43.0...v4.43.1) (2025-10-20)
### Bug Fixes
* **levels:** use two-column grid for kyu details to prevent clipping ([fa3b73c](https://github.com/antialias/soroban-abacus-flashcards/commit/fa3b73c69169b4694201ffa19ae3f8b5a68dfe32))
## [4.43.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.42.1...v4.43.0) (2025-10-20)
### Features
* **levels:** add structured kyu exam details with card UI ([6501b07](https://github.com/antialias/soroban-abacus-flashcards/commit/6501b073b100a00982cff1ca3140921e74f31a9c))
## [4.42.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.42.0...v4.42.1) (2025-10-20)
### Code Refactoring
* **levels:** store kyu data verbatim, add formatting layer ([53d23f1](https://github.com/antialias/soroban-abacus-flashcards/commit/53d23f19bc06459462afb76ed94d9b99d583a32d))
## [4.42.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.41.0...v4.42.0) (2025-10-20)
### Features
* **levels:** add kyu level details display with English translations ([c650ffa](https://github.com/antialias/soroban-abacus-flashcards/commit/c650ffa1935fe370d37190b2843c0deecdcce8e7))
## [4.41.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.40.1...v4.41.0) (2025-10-20)
### Features
* **levels:** right-align abacus display ([8681b17](https://github.com/antialias/soroban-abacus-flashcards/commit/8681b17340e757cf04d17f884a780a251645bb33))
## [4.40.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.40.0...v4.40.1) (2025-10-20)
### Bug Fixes
* **levels:** increase animation speed to 10ms for 10th Dan ([6f89d9e](https://github.com/antialias/soroban-abacus-flashcards/commit/6f89d9e274082908fc090a9c0ba310f2cb06f014))
## [4.40.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.39.1...v4.40.0) (2025-10-20)
### Features
* **levels:** progressive animation speed for Dan levels ([9dff3e7](https://github.com/antialias/soroban-abacus-flashcards/commit/9dff3e7b7b1ca46ea7f19a48135124b80c5182c0))
## [4.39.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.39.0...v4.39.1) (2025-10-20)
### Bug Fixes
* **levels:** improve slider tick spacing to use full width ([1e90d6c](https://github.com/antialias/soroban-abacus-flashcards/commit/1e90d6c6207f29084a8dc96ccfbb1013a1a62271))
## [4.39.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.38.1...v4.39.0) (2025-10-20)
### Features
* **levels:** add auto-advance slider with hover pause ([41eaed2](https://github.com/antialias/soroban-abacus-flashcards/commit/41eaed24fce510bab7fd03fa2e39e829b33a7346))
## [4.38.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.38.0...v4.38.1) (2025-10-20)
### Bug Fixes
* **levels:** adjust slider text positioning to prevent emoji overlap ([e5ffe39](https://github.com/antialias/soroban-abacus-flashcards/commit/e5ffe3927edfb1baea7ddd216507e081f50e5d2c))
## [4.38.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.37.0...v4.38.0) (2025-10-20)
### Features
* **levels:** add animated calculation effect to abacus display ([4f4c735](https://github.com/antialias/soroban-abacus-flashcards/commit/4f4c73577a944518c093b3208a85482909fe3064))
## [4.37.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.36.0...v4.37.0) (2025-10-20)
### Features
* **levels:** add hover tracking to slider for real-time level preview ([477a0b3](https://github.com/antialias/soroban-abacus-flashcards/commit/477a0b367e32749b865b5a5405846e86d5bcef6a))
## [4.36.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.35.1...v4.36.0) (2025-10-20)
### Features
* **levels:** make emoji tick marks clickable and remove redundant UI ([07c783a](https://github.com/antialias/soroban-abacus-flashcards/commit/07c783a79454f50e7302b19684be6d2e5930154d))
### Bug Fixes
* **levels:** add smooth CSS transitions for slider thumb movement ([ca8cef1](https://github.com/antialias/soroban-abacus-flashcards/commit/ca8cef1c36efeb1c8c214c74f8bd383f9295be3b))
## [4.35.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.35.0...v4.35.1) (2025-10-20)
### Features
* **abacus-react:** export StandaloneBead component wired to AbacusDisplayContext ([0146ce1](https://github.com/antialias/soroban-abacus-flashcards/commit/0146ce1e67da27a24cbaa8338ba6a1a6befd6bd3))
### Performance Improvements
* **levels:** speed up slider animations for more responsive feel ([1e5467f](https://github.com/antialias/soroban-abacus-flashcards/commit/1e5467fad4e27b832300c49b4f73547dc47598b0))
## [4.35.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.34.0...v4.35.0) (2025-10-20)
### Features
* **levels:** replace slider thumb with diamond-shaped abacus beads ([0fbde53](https://github.com/antialias/soroban-abacus-flashcards/commit/0fbde53039d3ea000c6a3be492b733479e7bf47c))
## [4.34.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.33.8...v4.34.0) (2025-10-20)
### Features
* **levels:** redesign slider with abacus-themed beads ([f3dce84](https://github.com/antialias/soroban-abacus-flashcards/commit/f3dce84532fa706e4ec9551facde2055a060ee13))
### Code Refactoring
* **levels:** convert to Radix UI Slider with abacus theme ([a03e73c](https://github.com/antialias/soroban-abacus-flashcards/commit/a03e73c849c5da4337f26a74b8f12b617c66068e))
## [4.33.8](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.33.7...v4.33.8) (2025-10-20)
### Bug Fixes
* **levels:** reduce Dan scale and container height to prevent clipping ([563136f](https://github.com/antialias/soroban-abacus-flashcards/commit/563136fb79fa10b2af3a119bf0f861e3b0812b2e))
* **levels:** reduce max scale factor to allow more compact container ([ead9ee9](https://github.com/antialias/soroban-abacus-flashcards/commit/ead9ee9589aa4d7376e9385da5da53a6b444858a))
## [4.33.7](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.33.6...v4.33.7) (2025-10-20)
### Bug Fixes
* **levels:** reduce scale factor variation to minimize margin differences ([abb647c](https://github.com/antialias/soroban-abacus-flashcards/commit/abb647ce40b8f9d0c8268ab18c139324ae3195c5))
## [4.33.6](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.33.5...v4.33.6) (2025-10-20)
### Bug Fixes
* **levels:** increase container height to prevent abacus clipping ([cd5c15a](https://github.com/antialias/soroban-abacus-flashcards/commit/cd5c15aeb260c568fe7ad9b6a4f51c4d6498b2b8))
## [4.33.5](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.33.4...v4.33.5) (2025-10-20)
### Bug Fixes
* **levels:** revert delayed column change, keep overflow hidden ([22f00f5](https://github.com/antialias/soroban-abacus-flashcards/commit/22f00f59f5facc36a846408dcd196ec54ea676b1))
## [4.33.4](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.33.3...v4.33.4) (2025-10-20)
### Bug Fixes
* **levels:** stabilize slider position and prevent abacus clipping ([09004dc](https://github.com/antialias/soroban-abacus-flashcards/commit/09004dc2c055031ee2f71c964ceee6f7b1d42ecd))
## [4.33.3](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.33.2...v4.33.3) (2025-10-20)
### Code Refactoring
* **levels:** move slider into level display pane above abacus ([2d8bb4a](https://github.com/antialias/soroban-abacus-flashcards/commit/2d8bb4ab8804f399d1ccc8a18feff9f09eca8029))
## [4.33.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.33.1...v4.33.2) (2025-10-20)
### Bug Fixes
* **levels:** add fixed height to entire level display pane ([200b26c](https://github.com/antialias/soroban-abacus-flashcards/commit/200b26c2cd35d1d637ede9dcfc3dbbc7f3f19320))
## [4.33.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.33.0...v4.33.1) (2025-10-20)
### Bug Fixes
* **levels:** only animate abacus, not container with background/border ([c80477d](https://github.com/antialias/soroban-abacus-flashcards/commit/c80477d24877ddada5f3f4405abbf05e1d753b5d))
## [4.33.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.32.1...v4.33.0) (2025-10-20)
### Features
* **abacus-react:** add BigInt support for 30-digit Dan level abacuses ([0ab4cc2](https://github.com/antialias/soroban-abacus-flashcards/commit/0ab4cc288066b75a6ea4371f65098db5c0fc8847))
* **levels:** add hover interaction and smooth React Spring transitions ([fd2b633](https://github.com/antialias/soroban-abacus-flashcards/commit/fd2b6338a84c3bbc683eff216a8da3b155749f0f))
## [4.32.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.32.0...v4.32.1) (2025-10-20)
### Bug Fixes
* **levels:** use correct dark mode styling from homepage + docs update ([c38767f](https://github.com/antialias/soroban-abacus-flashcards/commit/c38767f4d399fa2caa5cd4e0185689d0207fbdaf))
## [4.32.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.31.1...v4.32.0) (2025-10-20)
### Features
* **levels:** add dark mode styling and responsive scaling to abacus ([92e1e62](https://github.com/antialias/soroban-abacus-flashcards/commit/92e1e621321039206f65b3605f5797bbdc6beafc))
## [4.31.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.31.0...v4.31.1) (2025-10-20)
### Bug Fixes
* **levels:** use correct AbacusReact API with direct props ([892b377](https://github.com/antialias/soroban-abacus-flashcards/commit/892b377eb3bbd555dd2566bf58e946e9faa7b9f6))
## [4.31.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.30.0...v4.31.0) (2025-10-20)
### Features
* **levels:** implement interactive slider for exploring kyu & dan ranks ([eb3b100](https://github.com/antialias/soroban-abacus-flashcards/commit/eb3b1000563536d4143ba1f4ec04e59e8dd2e608))
## [4.30.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.29.0...v4.30.0) (2025-10-20)
### Features
* **levels:** create true horizontal slider with abacus visualizations ([6d734f1](https://github.com/antialias/soroban-abacus-flashcards/commit/6d734f1d51f5ba1367f55923e58bd977413d754e))
## [4.29.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.28.0...v4.29.0) (2025-10-20)
### Features
* **levels:** replace kyu grid with interactive slider and abacus visualizations ([10978e8](https://github.com/antialias/soroban-abacus-flashcards/commit/10978e890beee65dea78ddcce52cfe5315d58063))
## [4.28.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.27.0...v4.28.0) (2025-10-20)
### Features
* **levels:** add informational footer section ([0b1bff7](https://github.com/antialias/soroban-abacus-flashcards/commit/0b1bff7eab8f5da84ae309dbda336e168c2fe3fd))
## [4.27.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.26.0...v4.27.0) (2025-10-20)
### Features
* **levels:** add Dan levels ladder visualization ([c18012c](https://github.com/antialias/soroban-abacus-flashcards/commit/c18012cb505a1f2a86ebed7579b379a4d7d97f2c))
## [4.26.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.25.1...v4.26.0) (2025-10-20)
### Features
* **levels:** add kyu level data and cards ([6463a3b](https://github.com/antialias/soroban-abacus-flashcards/commit/6463a3b2f6371ebebac1048197fb44178997d2ef))
## [4.25.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.25.0...v4.25.1) (2025-10-20)
### Code Refactoring
* **homepage:** make entire "Your Journey" card clickable ([3f30810](https://github.com/antialias/soroban-abacus-flashcards/commit/3f30810271418f3acf3df17e41d9a897a3312c34))
## [4.25.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.24.3...v4.25.0) (2025-10-20)
### Features
* **levels:** add Kyu & Dan levels page with homepage link ([39b1e7d](https://github.com/antialias/soroban-abacus-flashcards/commit/39b1e7de16f15412c91cf648c714e31e2de7a6bc))
### Styles
* **homepage:** adjust journey emoji sizing and spacing ([2a0e469](https://github.com/antialias/soroban-abacus-flashcards/commit/2a0e469e83b99c88f091bfecd770e0b4c1cb6310))
## [4.24.3](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.24.2...v4.24.3) (2025-10-20)
### Code Refactoring
* **homepage:** align all skill icon panes horizontally ([4b04e86](https://github.com/antialias/soroban-abacus-flashcards/commit/4b04e8673da228863d4ec1869897ee431fa3d753))
## [4.24.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.24.1...v4.24.2) (2025-10-20)
### Code Refactoring
* **homepage:** tighten mini abacus vertical padding ([514d07e](https://github.com/antialias/soroban-abacus-flashcards/commit/514d07ecb5f65a3c0982b8e90994e1c17ebaa59c))
## [4.24.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.24.0...v4.24.1) (2025-10-20)
### Bug Fixes
* **homepage:** adjust mini abacus container height ([c4066d6](https://github.com/antialias/soroban-abacus-flashcards/commit/c4066d687925bbe7737ebfeefdada7365ff97c6c))
* **homepage:** fix MiniAbacus runtime error and improve sizing ([1fa0df8](https://github.com/antialias/soroban-abacus-flashcards/commit/1fa0df85f7d3988cbc61701d89476419ccf0a13c))
* **homepage:** use correct AbacusReact API and fix clipping/styling issues ([1432afd](https://github.com/antialias/soroban-abacus-flashcards/commit/1432afd6e6bd547bd0da76dbeea1c2b71244826f))
* **homepage:** use direct conditionals for mini abacus padding ([38ef16a](https://github.com/antialias/soroban-abacus-flashcards/commit/38ef16a8f91f8ab4ad0d717b0321e2002636fafb))
### Styles
* **homepage:** add more padding around mini abacus ([c5103d0](https://github.com/antialias/soroban-abacus-flashcards/commit/c5103d049f73a8f7ef26915edfbef9ea56d59094))
* **homepage:** balance mini abacus padding horizontally and vertically ([2f0304e](https://github.com/antialias/soroban-abacus-flashcards/commit/2f0304eb81cdf84c21b0554c9cd4bd5478896dd8))
* **homepage:** increase mini abacus padding to '5' ([1da9ed1](https://github.com/antialias/soroban-abacus-flashcards/commit/1da9ed1ce6995c605622fc2863f248e5e91ab9c3))
## [4.24.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.23.0...v4.24.0) (2025-10-20)
### Features
* **homepage:** add animated mini abacus to "Read and set numbers" card ([e028e34](https://github.com/antialias/soroban-abacus-flashcards/commit/e028e342ad4bc01491e05a4ba074628155926fd8))
## [4.23.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.22.0...v4.23.0) (2025-10-20)
### Features
* **homepage:** add more visual embellishments to learning cards ([4ec1b95](https://github.com/antialias/soroban-abacus-flashcards/commit/4ec1b952f202d50f6db287c41732ec65ca17c142))
## [4.22.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.21.1...v4.22.0) (2025-10-20)
### Features
* **homepage:** enhance "What You'll Learn" with visual cards ([d142342](https://github.com/antialias/soroban-abacus-flashcards/commit/d1423420e653b26b2f89d9d17ae5d597807d6979))
### Bug Fixes
* **tutorial:** reduce tooltip z-index to scroll under nav bar ([47640f3](https://github.com/antialias/soroban-abacus-flashcards/commit/47640f3486c6d4a7107d59bdcce043f76fabbb1d))
## [4.21.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.21.0...v4.21.1) (2025-10-20)
### Code Refactoring
* **homepage:** rearrange tutorial demo layout side by side ([8b4ecee](https://github.com/antialias/soroban-abacus-flashcards/commit/8b4eceebfaaaf07e38ea64c7fe015aec86ac754f))
## [4.21.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.20.7...v4.21.0) (2025-10-20)
### Features
* **tutorial:** add silentErrors prop to suppress error messages ([8835e1c](https://github.com/antialias/soroban-abacus-flashcards/commit/8835e1c57ab8adcecefe0db082360dd98fbfaac7))
## [4.20.7](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.20.6...v4.20.7) (2025-10-20)
### Bug Fixes
* **home:** use Panda CSS token() for dynamic colors and center arrows properly ([d52ba63](https://github.com/antialias/soroban-abacus-flashcards/commit/d52ba6373a4577655dc1e5f5ff4926af7f7d96c3))
## [4.20.6](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.20.5...v4.20.6) (2025-10-20)
### Bug Fixes
* **homepage:** use inline styles for journey level colors ([5d85e89](https://github.com/antialias/soroban-abacus-flashcards/commit/5d85e898d65d44d8d09bee952fad44b5a9c0cd20)), closes [#4ade80](https://github.com/antialias/soroban-abacus-flashcards/issues/4ade80) [#60a5](https://github.com/antialias/soroban-abacus-flashcards/issues/60a5) [#a78](https://github.com/antialias/soroban-abacus-flashcards/issues/a78) [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24)
## [4.20.5](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.20.4...v4.20.5) (2025-10-20)
### Bug Fixes
* **docker:** include Panda CSS styled-system in production image ([57fabff](https://github.com/antialias/soroban-abacus-flashcards/commit/57fabffe605d953b4a4d7e05032401cbf1ab2d14))
## [4.20.4](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.20.3...v4.20.4) (2025-10-19)
### Bug Fixes
* **homepage:** use inline styles for Your Journey text contrast ([8e51390](https://github.com/antialias/soroban-abacus-flashcards/commit/8e5139001818d7013e1b2654ac707f7429316d58)), closes [#e5e7](https://github.com/antialias/soroban-abacus-flashcards/issues/e5e7) [#e5e7](https://github.com/antialias/soroban-abacus-flashcards/issues/e5e7) [#9ca3](https://github.com/antialias/soroban-abacus-flashcards/issues/9ca3) [#d1d5](https://github.com/antialias/soroban-abacus-flashcards/issues/d1d5)
## [4.20.3](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.20.2...v4.20.3) (2025-10-19)
### Bug Fixes
* **homepage:** use explicit RGBA colors for Your Journey text ([9c51cc9](https://github.com/antialias/soroban-abacus-flashcards/commit/9c51cc94eec4efcab9c0b9d1190f5b79c0c7d365))
## [4.20.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.20.1...v4.20.2) (2025-10-19)

View File

@@ -59,6 +59,9 @@ RUN adduser --system --uid 1001 nextjs
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next ./apps/web/.next
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/public ./apps/web/public
# Copy Panda CSS generated styles
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/styled-system ./apps/web/styled-system
# Copy server files (compiled from TypeScript)
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/server.js ./apps/web/
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/dist ./apps/web/dist

View File

@@ -121,6 +121,62 @@ className="bg-blue-200 border-gray-300 text-brand-600"
See `.claude/GAME_THEMES.md` for standardized color theme usage in arcade games.
## Abacus Visualizations
**CRITICAL: This project uses @soroban/abacus-react for all abacus visualizations.**
- All abacus displays MUST use components from `@soroban/abacus-react`
- Package location: `packages/abacus-react`
- Main components: `AbacusReact`, `useAbacusConfig`, `useAbacusDisplay`
- DO NOT create custom abacus visualizations
- DO NOT manually draw abacus columns, beads, or bars
**Common Mistakes to Avoid:**
- ❌ Don't create custom abacus components or SVGs
- ❌ Don't manually render abacus beads or columns
- ✅ Always use `AbacusReact` from `@soroban/abacus-react`
- ✅ Use `useAbacusConfig` for abacus configuration
- ✅ Use `useAbacusDisplay` for reading abacus state
**MANDATORY: Read the Docs Before Customizing**
**ALWAYS read the full README documentation before customizing or styling AbacusReact:**
- Location: `packages/abacus-react/README.md`
- Check homepage implementation: `src/app/page.tsx` (MiniAbacus component)
- Check storybook examples: `src/stories/AbacusReact.*.stories.tsx`
**Key Documentation Points:**
1. **Custom Styles**: Use `fill` (not just `stroke`) for columnPosts and reckoningBar
2. **Props**: Use direct props like `value`, `columns`, `scaleFactor` (not config objects)
3. **Example from Homepage:**
```typescript
const darkStyles = {
columnPosts: {
fill: 'rgba(255, 255, 255, 0.3)',
stroke: 'rgba(255, 255, 255, 0.2)',
strokeWidth: 2,
},
reckoningBar: {
fill: 'rgba(255, 255, 255, 0.4)',
stroke: 'rgba(255, 255, 255, 0.25)',
strokeWidth: 3,
},
}
<AbacusReact
value={123}
columns={3}
customStyles={darkStyles}
/>
```
**Example Usage:**
```typescript
import { AbacusReact } from '@soroban/abacus-react'
<AbacusReact value={123} columns={5} scaleFactor={1.5} showNumbers={true} />
```
## Known Issues
### @soroban/abacus-react TypeScript Module Resolution

View File

@@ -0,0 +1,76 @@
# Panda CSS Dynamic Token Usage
## Problem: Dynamic Color Tokens Not Working
When using Panda CSS, color tokens like `blue.400`, `purple.400`, etc. don't work when used dynamically through variables in the `css()` function.
## Root Cause
Panda CSS's `css()` function requires **static values at build time**. It cannot process dynamic token references like:
```typescript
// ❌ This doesn't work
const color = 'blue.400'
css({ color: color }) // Panda can't resolve this at build time
```
The `css()` function performs static analysis during the build process to generate CSS classes. It cannot handle runtime-dynamic token paths.
## Solution: Use the `token()` Function
Panda CSS provides a `token()` function specifically for resolving token paths to their actual values at runtime:
```typescript
import { token } from '../../styled-system/tokens'
// ✅ This works
const stages = [
{ level: '10 Kyu', label: 'Beginner', color: 'colors.green.400' },
{ level: '5 Kyu', label: 'Intermediate', color: 'colors.blue.400' },
{ level: '1 Kyu', label: 'Advanced', color: 'colors.violet.400' },
{ level: 'Dan', label: 'Master', color: 'colors.amber.400' },
] as const
// Use with inline styles, not css()
<div style={{ color: token(stage.color) }}>
```
## Important Notes
1. **Use `as const`**: TypeScript needs the array marked as `const` so the token strings are treated as literal types, not generic strings. The `token()` function expects the `Token` literal type.
2. **Use inline styles**: When using `token()`, apply colors via the `style` prop, not through the `css()` function:
```typescript
// ✅ Correct
<div style={{ color: token(stage.color) }}>
// ❌ Won't work
<div className={css({ color: token(stage.color) })}>
```
3. **Static tokens in css()**: For static usage, you CAN use tokens directly in `css()`:
```typescript
// ✅ This works because it's static
css({ color: 'blue.400' })
```
## How token() Works
The `token()` function:
- Takes a token path like `"colors.blue.400"`
- Looks it up in the generated token registry (`styled-system/tokens/index.mjs`)
- Returns the actual CSS value (e.g., `"#60a5fa"`)
- Happens at runtime, not build time
## Token Type Definition
The `Token` type is a union of all valid token paths:
```typescript
type Token = "colors.blue.400" | "colors.green.400" | "colors.violet.400" | ...
```
This is defined in `styled-system/tokens/tokens.d.ts`.
## Reference Implementation
See `src/app/page.tsx` lines 404-434 for a working example of dynamic token usage in the "Your Journey" section.

View File

@@ -16,7 +16,11 @@ function GamesPageContent() {
const router = useRouter()
// Get all players sorted by creation time
const allPlayers = getAllPlayers().sort((a, b) => a.createdAt - b.createdAt)
const allPlayers = getAllPlayers().sort((a, b) => {
const aTime = a.createdAt instanceof Date ? a.createdAt.getTime() : a.createdAt
const bTime = b.createdAt instanceof Date ? b.createdAt.getTime() : b.createdAt
return aTime - bTime
})
return (
<div

View File

@@ -0,0 +1,958 @@
'use client'
import { useState, useEffect } from 'react'
import { useSpring, useTransition, animated } from '@react-spring/web'
import * as Slider from '@radix-ui/react-slider'
import { AbacusReact, StandaloneBead } from '@soroban/abacus-react'
import { PageWithNav } from '@/components/PageWithNav'
import { css } from '../../../styled-system/css'
import { container, stack } from '../../../styled-system/patterns'
import { kyuLevelDetails } from '@/data/kyuLevelDetails'
// Combine all levels into one array for the slider
const allLevels = [
{
level: '10th Kyu',
emoji: '🧒',
color: 'green',
digits: 2,
type: 'kyu' as const,
},
{
level: '9th Kyu',
emoji: '🧒',
color: 'green',
digits: 2,
type: 'kyu' as const,
},
{
level: '8th Kyu',
emoji: '🧒',
color: 'green',
digits: 3,
type: 'kyu' as const,
},
{
level: '7th Kyu',
emoji: '🧒',
color: 'green',
digits: 4,
type: 'kyu' as const,
},
{
level: '6th Kyu',
emoji: '🧑',
color: 'blue',
digits: 5,
type: 'kyu' as const,
},
{
level: '5th Kyu',
emoji: '🧑',
color: 'blue',
digits: 6,
type: 'kyu' as const,
},
{
level: '4th Kyu',
emoji: '🧑',
color: 'blue',
digits: 7,
type: 'kyu' as const,
},
{
level: '3rd Kyu',
emoji: '🧔',
color: 'violet',
digits: 8,
type: 'kyu' as const,
},
{
level: '2nd Kyu',
emoji: '🧔',
color: 'violet',
digits: 9,
type: 'kyu' as const,
},
{
level: '1st Kyu',
emoji: '🧔',
color: 'violet',
digits: 10,
type: 'kyu' as const,
},
{
level: 'Pre-1st Dan',
name: 'Jun-Shodan',
minScore: 90,
emoji: '🧙',
color: 'amber',
digits: 30,
type: 'dan' as const,
},
{
level: '1st Dan',
name: 'Shodan',
minScore: 100,
emoji: '🧙',
color: 'amber',
digits: 30,
type: 'dan' as const,
},
{
level: '2nd Dan',
name: 'Nidan',
minScore: 120,
emoji: '🧙‍♂️',
color: 'amber',
digits: 30,
type: 'dan' as const,
},
{
level: '3rd Dan',
name: 'Sandan',
minScore: 140,
emoji: '🧙‍♂️',
color: 'amber',
digits: 30,
type: 'dan' as const,
},
{
level: '4th Dan',
name: 'Yondan',
minScore: 160,
emoji: '🧙‍♀️',
color: 'amber',
digits: 30,
type: 'dan' as const,
},
{
level: '5th Dan',
name: 'Godan',
minScore: 180,
emoji: '🧙‍♀️',
color: 'amber',
digits: 30,
type: 'dan' as const,
},
{
level: '6th Dan',
name: 'Rokudan',
minScore: 200,
emoji: '🧝',
color: 'amber',
digits: 30,
type: 'dan' as const,
},
{
level: '7th Dan',
name: 'Nanadan',
minScore: 220,
emoji: '🧝',
color: 'amber',
digits: 30,
type: 'dan' as const,
},
{
level: '8th Dan',
name: 'Hachidan',
minScore: 250,
emoji: '🧝‍♂️',
color: 'amber',
digits: 30,
type: 'dan' as const,
},
{
level: '9th Dan',
name: 'Kudan',
minScore: 270,
emoji: '🧝‍♀️',
color: 'amber',
digits: 30,
type: 'dan' as const,
},
{
level: '10th Dan',
name: 'Judan',
minScore: 290,
emoji: '👑',
color: 'amber',
digits: 30,
type: 'dan' as const,
},
] as const
// Helper function to map level names to kyuLevelDetails keys
function getLevelDetailsKey(levelName: string): string | null {
// Convert "10th Kyu" → "10-kyu", "3rd Kyu" → "3-kyu", etc.
const match = levelName.match(/^(\d+)(?:st|nd|rd|th)\s+Kyu$/)
if (match) {
return `${match[1]}-kyu`
}
return null
}
// Parse and format kyu level details into structured sections with icons
function parseKyuDetails(rawText: string) {
const lines = rawText.split('\n').filter((line) => line.trim() && !line.includes('shuzan.jp'))
// Always return sections in consistent order: Add/Sub, Multiply, Divide
const sections: Array<{
type: 'addSub' | 'multiply' | 'divide'
icon: string
label: string
digits: string | null
rows: string | null
chars: string | null
problems: string | null
}> = [
{
type: 'addSub',
icon: '',
label: 'Add/Sub',
digits: null,
rows: null,
chars: null,
problems: null,
},
{
type: 'multiply',
icon: '✖️',
label: 'Multiply',
digits: null,
rows: null,
chars: null,
problems: null,
},
{
type: 'divide',
icon: '➗',
label: 'Divide',
digits: null,
rows: null,
chars: null,
problems: null,
},
]
for (const line of lines) {
if (line.includes('Add/Sub:')) {
const match = line.match(/(\d+)-digit.*?(\d+)口.*?(\d+)字/)
if (match) {
sections[0].digits = match[1]
sections[0].rows = match[2]
sections[0].chars = match[3]
}
} else if (line.includes('×:')) {
const match = line.match(/(\d+) digits.*?\((\d+)/)
if (match) {
sections[1].digits = match[1]
sections[1].problems = match[2]
}
} else if (line.includes('÷:')) {
const match = line.match(/(\d+) digits.*?\((\d+)/)
if (match) {
sections[2].digits = match[1]
sections[2].problems = match[2]
}
}
}
return sections
}
export default function LevelsPage() {
const [currentIndex, setCurrentIndex] = useState(0)
const [isHovering, setIsHovering] = useState(false)
const [isPaneHovered, setIsPaneHovered] = useState(false)
const currentLevel = allLevels[currentIndex]
// State for animated abacus digits
const [animatedDigits, setAnimatedDigits] = useState<string>('')
// Initialize animated digits when level changes
useEffect(() => {
const generateRandomDigits = (numDigits: number) => {
return Array.from({ length: numDigits }, () => Math.floor(Math.random() * 10)).join('')
}
setAnimatedDigits(generateRandomDigits(currentLevel.digits))
}, [currentLevel.digits])
// Animate abacus calculations - speed increases with Dan level
useEffect(() => {
// Calculate animation speed based on level
// Kyu levels: 500ms
// Pre-1st Dan: 500ms
// 1st-10th Dan: interpolate from 500ms to 10ms
const getAnimationInterval = () => {
if (currentIndex < 11) {
// Kyu levels and Pre-1st Dan: constant 500ms
return 500
}
// 1st Dan through 10th Dan: speed up from 500ms to 10ms
// Index 11 (1st Dan) → 500ms
// Index 20 (10th Dan) → 10ms
const danProgress = (currentIndex - 11) / 9 // 0.0 to 1.0
return 500 - danProgress * 490 // 500ms down to 10ms
}
const intervalMs = getAnimationInterval()
const interval = setInterval(() => {
setAnimatedDigits((prev) => {
const digits = prev.split('').map(Number)
const numColumns = digits.length
// Pick 1-3 adjacent columns to change (grouping effect)
const groupSize = Math.floor(Math.random() * 3) + 1
const startCol = Math.floor(Math.random() * (numColumns - groupSize + 1))
// Change the selected columns
for (let i = startCol; i < startCol + groupSize && i < numColumns; i++) {
digits[i] = Math.floor(Math.random() * 10)
}
return digits.join('')
})
}, intervalMs)
return () => clearInterval(interval)
}, [currentIndex])
// Auto-advance slider position every 3 seconds (unless pane is hovered)
useEffect(() => {
if (isPaneHovered) return // Don't auto-advance when mouse is over the pane
const interval = setInterval(() => {
setCurrentIndex((prev) => {
// Cycle back to 0 when reaching the end
return prev >= allLevels.length - 1 ? 0 : prev + 1
})
}, 3000)
return () => clearInterval(interval)
}, [isPaneHovered])
// Handle hover on slider track
const handleSliderHover = (e: React.MouseEvent<HTMLSpanElement>) => {
const rect = e.currentTarget.getBoundingClientRect()
const x = e.clientX - rect.left
const percentage = x / rect.width
const index = Math.round(percentage * (allLevels.length - 1))
setCurrentIndex(Math.max(0, Math.min(allLevels.length - 1, index)))
}
// Calculate scale factor based on number of columns to fit the page
// Use constrained range to prevent huge size differences between levels
// Min 1.2 (for 30-column Dan levels) to Max 2.0 (for 2-column Kyu levels)
const scaleFactor = Math.max(1.2, Math.min(2.0, 20 / currentLevel.digits))
// Animate scale factor with React Spring for smooth transitions
const animatedProps = useSpring({
scaleFactor,
config: { tension: 350, friction: 45 },
})
// Animate emoji with proper cross-fade (old fades out, new fades in)
const emojiTransitions = useTransition(currentLevel.emoji, {
keys: currentIndex,
from: { opacity: 0 },
enter: { opacity: 1 },
leave: { opacity: 0 },
config: { duration: 120 },
})
// Convert animated digits to a number/BigInt for the abacus display
// Use BigInt for large numbers to get full 30-digit precision
const displayValue =
animatedDigits.length > 15
? BigInt(animatedDigits || '0')
: Number.parseInt(animatedDigits || '0', 10)
// Dark theme styles matching the homepage
const darkStyles = {
columnPosts: {
fill: 'rgba(255, 255, 255, 0.3)',
stroke: 'rgba(255, 255, 255, 0.2)',
strokeWidth: 2,
},
reckoningBar: {
fill: 'rgba(255, 255, 255, 0.4)',
stroke: 'rgba(255, 255, 255, 0.25)',
strokeWidth: 3,
},
}
return (
<PageWithNav navTitle="Kyu & Dan Levels" navEmoji="📊">
<div className={css({ bg: 'gray.900', minHeight: '100vh', pb: '12' })}>
{/* Hero Section */}
<div
className={css({
background:
'linear-gradient(135deg, rgba(17, 24, 39, 1) 0%, rgba(124, 58, 237, 0.3) 50%, rgba(17, 24, 39, 1) 100%)',
color: 'white',
py: { base: '12', md: '16' },
position: 'relative',
overflow: 'hidden',
})}
>
<div
className={css({
position: 'absolute',
inset: 0,
opacity: 0.1,
backgroundImage:
'radial-gradient(circle at 2px 2px, rgba(255, 255, 255, 0.15) 1px, transparent 0)',
backgroundSize: '40px 40px',
})}
/>
<div
className={container({
maxW: '6xl',
px: '4',
position: 'relative',
})}
>
<div className={css({ textAlign: 'center', maxW: '5xl', mx: 'auto' })}>
<h1
className={css({
fontSize: { base: '3xl', md: '5xl', lg: '6xl' },
fontWeight: 'bold',
mb: '4',
lineHeight: 'tight',
background: 'linear-gradient(135deg, #fbbf24 0%, #f59e0b 50%, #fbbf24 100%)',
backgroundClip: 'text',
color: 'transparent',
})}
>
Understanding Kyu & Dan Levels
</h1>
<p
className={css({
fontSize: { base: 'lg', md: 'xl' },
color: 'gray.300',
mb: '6',
maxW: '3xl',
mx: 'auto',
lineHeight: '1.6',
})}
>
Slide through the complete progression from beginner to master
</p>
</div>
</div>
</div>
{/* Main content */}
<div className={container({ maxW: '6xl', px: '4', py: '12' })}>
<section className={stack({ gap: '8' })}>
{/* Current Level Display */}
<div
onMouseEnter={() => setIsPaneHovered(true)}
onMouseLeave={() => setIsPaneHovered(false)}
className={css({
bg: 'transparent',
border: '2px solid',
borderColor:
currentLevel.color === 'green'
? 'green.500'
: currentLevel.color === 'blue'
? 'blue.500'
: currentLevel.color === 'violet'
? 'violet.500'
: 'amber.500',
rounded: 'xl',
p: { base: '6', md: '8' },
height: { base: 'auto', md: '700px' },
display: 'flex',
flexDirection: 'column',
})}
>
{/* Abacus-themed Radix Slider */}
<div className={css({ mb: '6', px: { base: '2', md: '8' } })}>
<div className={css({ position: 'relative', py: '12' })}>
{/* Emoji tick marks */}
<div
className={css({
position: 'absolute',
top: '0',
left: '0',
right: '0',
h: 'full',
display: 'flex',
alignItems: 'center',
pointerEvents: 'none',
px: '0', // Use full width for tick spacing
})}
>
<div
className={css({
position: 'relative',
w: 'full',
display: 'flex',
justifyContent: 'space-between',
})}
>
{allLevels.map((level, index) => (
<div
key={index}
onClick={() => setCurrentIndex(index)}
className={css({
fontSize: '4xl',
opacity: index === currentIndex ? '1' : '0.3',
transition: 'all 0.2s',
cursor: 'pointer',
pointerEvents: 'auto',
_hover: { opacity: index === currentIndex ? '1' : '0.6' },
})}
>
{level.emoji}
</div>
))}
</div>
</div>
<Slider.Root
value={[currentIndex]}
onValueChange={([value]) => setCurrentIndex(value)}
min={0}
max={allLevels.length - 1}
step={1}
onMouseMove={handleSliderHover}
onMouseEnter={() => setIsHovering(true)}
onMouseLeave={() => setIsHovering(false)}
className={css({
position: 'relative',
display: 'flex',
alignItems: 'center',
userSelect: 'none',
touchAction: 'none',
w: 'full',
h: '32',
cursor: 'pointer',
})}
>
<Slider.Track
className={css({
bg: 'rgba(255, 255, 255, 0.2)',
position: 'relative',
flexGrow: 1,
rounded: 'full',
h: '3px',
})}
>
<Slider.Range className={css({ display: 'none' })} />
</Slider.Track>
<Slider.Thumb
className={css({
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
position: 'relative',
w: '180px',
h: '128px',
bg: 'transparent',
cursor: 'grab',
transition: 'transform 0.15s ease-out, left 0.3s ease-out',
zIndex: 10,
_hover: { transform: 'scale(1.15)' },
_focus: {
outline: 'none',
transform: 'scale(1.15)',
},
_active: { cursor: 'grabbing' },
})}
>
<div className={css({ opacity: 0.75 })}>
<StandaloneBead
size={128}
color={currentLevel.color === 'violet' ? '#8b5cf6' : '#22c55e'}
animated={false}
/>
</div>
{emojiTransitions((style, emoji) => (
<animated.div
style={style}
className={css({
position: 'absolute',
fontSize: '9xl',
pointerEvents: 'none',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
})}
>
{emoji}
</animated.div>
))}
{/* Level text as part of the bead display */}
<div
className={css({
position: 'absolute',
bottom: '-80px',
left: '50%',
transform: 'translateX(-50%)',
textAlign: 'center',
pointerEvents: 'none',
whiteSpace: 'nowrap',
})}
>
<h2
className={css({
fontSize: '2xl',
fontWeight: 'bold',
color:
currentLevel.color === 'green'
? 'green.400'
: currentLevel.color === 'blue'
? 'blue.400'
: currentLevel.color === 'violet'
? 'violet.400'
: 'amber.400',
mb: '0.5',
})}
>
{currentLevel.level}
</h2>
{'name' in currentLevel && (
<div
className={css({
fontSize: 'md',
color: 'gray.300',
mb: '0.5',
})}
>
{currentLevel.name}
</div>
)}
{'minScore' in currentLevel && (
<div className={css({ fontSize: 'sm', color: 'gray.400' })}>
Min: {currentLevel.minScore}pts
</div>
)}
</div>
</Slider.Thumb>
</Slider.Root>
</div>
{/* Level Markers */}
<div
className={css({
display: 'flex',
justifyContent: 'space-between',
mt: '1',
fontSize: 'xs',
color: 'gray.500',
})}
>
<span>10th Kyu</span>
<span>1st Kyu</span>
<span>10th Dan</span>
</div>
</div>
{/* Abacus Display with Level Details */}
<div
className={css({
display: 'flex',
gap: '4',
p: '6',
bg: 'rgba(0, 0, 0, 0.3)',
rounded: 'lg',
border: '1px solid',
borderColor: 'gray.700',
overflow: 'hidden',
flex: 1,
})}
>
{/* Level Details (only for Kyu levels) */}
{currentLevel.type === 'kyu' &&
(() => {
const detailsKey = getLevelDetailsKey(currentLevel.level)
const rawText = detailsKey
? kyuLevelDetails[detailsKey as keyof typeof kyuLevelDetails]
: null
const sections = rawText ? parseKyuDetails(rawText) : []
// Use consistent sizing across all levels
const sizing = { fontSize: 'md', gap: '3', iconSize: '4xl' }
return sections.length > 0 ? (
<div
className={css({
flex: '0 0 auto',
display: 'grid',
gridTemplateColumns: 'repeat(2, 1fr)',
gap: '2',
p: '2',
maxW: '400px',
alignContent: 'center',
})}
>
{sections.map((section, idx) => {
const hasData = section.digits !== null
const levelColor =
currentLevel.color === 'green'
? 'green.300'
: currentLevel.color === 'blue'
? 'blue.300'
: 'violet.300'
return (
<div
key={idx}
className={css({
bg: hasData ? 'rgba(0, 0, 0, 0.4)' : 'rgba(0, 0, 0, 0.2)',
border: '1px solid',
borderColor: hasData ? 'gray.700' : 'gray.800',
rounded: 'md',
p: '3',
transition: 'all 0.2s',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
gap: '1.5',
opacity: hasData ? 1 : 0.3,
width: '170px',
height: '150px',
_hover: hasData
? {
borderColor: 'gray.500',
transform: 'scale(1.05)',
}
: {},
})}
>
<span className={css({ fontSize: sizing.iconSize, lineHeight: '1' })}>
{section.icon}
</span>
{hasData && section.digits && (
<>
<div
className={css({
fontSize: '2xl',
fontWeight: 'bold',
color: levelColor,
})}
>
{section.digits} digits
</div>
{(section.rows || section.chars) && (
<div
className={css({
fontSize: 'sm',
color: 'gray.400',
textAlign: 'center',
})}
>
{section.rows && `${section.rows} rows`}
{section.rows && section.chars && ' • '}
{section.chars && `${section.chars} chars`}
</div>
)}
{section.problems && (
<div
className={css({
fontSize: 'sm',
color: 'gray.400',
textAlign: 'center',
})}
>
{section.problems} problems
</div>
)}
</>
)}
<div
className={css({
fontSize: 'xs',
color: hasData ? 'gray.500' : 'gray.700',
textAlign: 'center',
fontWeight: hasData ? 'normal' : 'bold',
})}
>
{section.label}
</div>
</div>
)
})}
</div>
) : null
})()}
{/* Abacus (right-aligned for Kyu, centered for Dan) */}
<div
className={css({
display: 'flex',
justifyContent: currentLevel.type === 'kyu' ? 'flex-end' : 'center',
alignItems: 'center',
flex: 1,
})}
>
<animated.div
style={{
transform: animatedProps.scaleFactor.to((s) => `scale(${s / scaleFactor})`),
}}
>
<AbacusReact
value={displayValue}
columns={currentLevel.digits}
scaleFactor={scaleFactor}
showNumbers={true}
customStyles={darkStyles}
/>
</animated.div>
</div>
</div>
{/* Digit Count */}
<div
className={css({
textAlign: 'center',
color: 'gray.400',
fontSize: 'sm',
})}
>
Requires mastery of <strong>{currentLevel.digits}-digit</strong> calculations
</div>
</div>
{/* Legend */}
<div
className={css({
display: 'flex',
flexWrap: 'wrap',
gap: '6',
justifyContent: 'center',
p: '6',
bg: 'rgba(0, 0, 0, 0.3)',
rounded: 'lg',
border: '1px solid',
borderColor: 'gray.700',
})}
>
<div
className={css({
display: 'flex',
alignItems: 'center',
gap: '2',
})}
>
<div
className={css({
w: '4',
h: '4',
bg: 'green.500',
rounded: 'sm',
})}
/>
<span className={css({ fontSize: 'sm', color: 'gray.300' })}>
Beginner (10-7 Kyu)
</span>
</div>
<div
className={css({
display: 'flex',
alignItems: 'center',
gap: '2',
})}
>
<div
className={css({
w: '4',
h: '4',
bg: 'blue.500',
rounded: 'sm',
})}
/>
<span className={css({ fontSize: 'sm', color: 'gray.300' })}>
Intermediate (6-4 Kyu)
</span>
</div>
<div
className={css({
display: 'flex',
alignItems: 'center',
gap: '2',
})}
>
<div
className={css({
w: '4',
h: '4',
bg: 'violet.500',
rounded: 'sm',
})}
/>
<span className={css({ fontSize: 'sm', color: 'gray.300' })}>
Advanced (3-1 Kyu)
</span>
</div>
<div
className={css({
display: 'flex',
alignItems: 'center',
gap: '2',
})}
>
<div
className={css({
w: '4',
h: '4',
bg: 'amber.500',
rounded: 'sm',
})}
/>
<span className={css({ fontSize: 'sm', color: 'gray.300' })}>
Master (Dan ranks)
</span>
</div>
</div>
{/* Info Section */}
<div
className={css({
bg: 'rgba(0, 0, 0, 0.4)',
border: '1px solid',
borderColor: 'gray.700',
rounded: 'xl',
p: { base: '6', md: '8' },
})}
>
<h3
className={css({
fontSize: { base: 'xl', md: '2xl' },
fontWeight: 'bold',
color: 'white',
mb: '4',
})}
>
About This Ranking System
</h3>
<div className={stack({ gap: '4' })}>
<p className={css({ color: 'gray.300', lineHeight: '1.6' })}>
This ranking system is based on the official examination structure used by the{' '}
<strong className={css({ color: 'white' })}>Japan Abacus Federation</strong>. It
represents a standardized progression from beginner (10th Kyu) to master level
(10th Dan), used internationally for soroban proficiency assessment.
</p>
<p className={css({ color: 'gray.300', lineHeight: '1.6' })}>
The system is designed to gradually increase in difficulty. Kyu levels progress
from 2-digit calculations at 10th Kyu to 10-digit calculations at 1st Kyu. Dan
levels all require mastery of 30-digit calculations, with ranks awarded based on
exam scores.
</p>
</div>
</div>
</section>
</div>
</div>
</PageWithNav>
)
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,41 @@
'use client'
import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
import * as Tooltip from '@radix-ui/react-tooltip'
import Link from 'next/link'
import { usePathname, useRouter } from 'next/navigation'
import React, { useState } from 'react'
import React, { useContext, useMemo, useState } from 'react'
import { css } from '../../styled-system/css'
import { container, hstack } from '../../styled-system/patterns'
import { Z_INDEX } from '../constants/zIndex'
import { useFullscreen } from '../contexts/FullscreenContext'
import { getRandomSubtitle } from '../data/abaciOneSubtitles'
import { AbacusDisplayDropdown } from './AbacusDisplayDropdown'
// Import HomeHeroContext for optional usage
import type { Subtitle } from '../data/abaciOneSubtitles'
type HomeHeroContextValue = {
subtitle: Subtitle
isHeroVisible: boolean
} | null
// HomeHeroContext - imported dynamically to avoid circular deps
let HomeHeroContextModule: any = null
try {
HomeHeroContextModule = require('../contexts/HomeHeroContext')
} catch {
// Context not available
}
const HomeHeroContext: React.Context<HomeHeroContextValue> =
HomeHeroContextModule?.HomeHeroContext || React.createContext<HomeHeroContextValue>(null)
// Use HomeHeroContext without requiring it
function useOptionalHomeHero(): HomeHeroContextValue {
return useContext(HomeHeroContext)
}
interface AppNavBarProps {
variant?: 'full' | 'minimal'
navSlot?: React.ReactNode
@@ -514,6 +540,17 @@ export function AppNavBar({ variant = 'full', navSlot }: AppNavBarProps) {
const isArcadePage = pathname?.startsWith('/arcade')
const { isFullscreen, toggleFullscreen, exitFullscreen } = useFullscreen()
// Try to get home hero context (if on homepage)
const homeHero = useOptionalHomeHero()
// Select a random subtitle once on mount (performance: won't change on re-renders)
// Use homeHero subtitle if available, otherwise generate one
const fallbackSubtitle = useMemo(() => getRandomSubtitle(), [])
const subtitle = homeHero?.subtitle || fallbackSubtitle
// Show branding unless we're on homepage with visible hero
const showBranding = !homeHero || !homeHero.isHeroVisible
// Auto-detect variant based on context
const actualVariant = variant === 'full' && (isGamePage || isArcadePage) ? 'minimal' : variant
@@ -532,54 +569,135 @@ export function AppNavBar({ variant = 'full', navSlot }: AppNavBarProps) {
)
}
// Check if we should use transparent styling (when hero is visible)
const isTransparent = homeHero?.isHeroVisible
return (
<header
className={css({
bg: 'white',
shadow: 'sm',
borderBottom: '1px solid',
borderColor: 'gray.200',
position: 'sticky',
top: 0,
zIndex: 30,
})}
>
<div className={container({ maxW: '7xl', px: '4', py: '3' })}>
<div className={hstack({ justify: 'space-between', alignItems: 'center' })}>
{/* Logo */}
<Link
href="/"
className={css({
fontSize: 'xl',
fontWeight: 'bold',
color: 'brand.800',
textDecoration: 'none',
_hover: { color: 'brand.900' },
})}
>
🧮 Soroban Generator
</Link>
<Tooltip.Provider delayDuration={200}>
<header
className={css({
bg: isTransparent ? 'transparent' : 'white',
shadow: isTransparent ? 'none' : 'sm',
borderBottom: isTransparent ? 'none' : '1px solid',
borderColor: isTransparent ? 'transparent' : 'gray.200',
position: 'fixed',
top: 0,
left: 0,
right: 0,
zIndex: 1000,
transition: 'all 0.3s ease',
})}
>
<div className={container({ maxW: '7xl', px: '4', py: '3' })}>
<div className={hstack({ justify: 'space-between', alignItems: 'center' })}>
{/* Logo - conditionally shown based on hero visibility */}
{showBranding ? (
<Link
href="/"
className={css({
display: 'flex',
flexDirection: 'column',
gap: '0',
textDecoration: 'none',
_hover: { '& > .brand-name': { color: 'brand.900' } },
opacity: 0,
animation: 'fadeIn 0.3s ease-out forwards',
})}
>
<span
className={css({
fontSize: 'xl',
fontWeight: 'bold',
color: 'brand.800',
})}
>
🧮 Abaci One
</span>
<Tooltip.Root>
<Tooltip.Trigger asChild>
<span
className={css({
fontSize: 'xs',
fontWeight: 'medium',
color: 'brand.600',
fontStyle: 'italic',
cursor: 'help',
_hover: { color: 'brand.700' },
})}
>
{subtitle.text}
</span>
</Tooltip.Trigger>
<Tooltip.Portal>
<Tooltip.Content
side="bottom"
align="start"
sideOffset={4}
className={css({
bg: 'gray.900',
color: 'white',
px: '3',
py: '2',
rounded: 'md',
fontSize: 'sm',
maxW: '250px',
shadow: 'lg',
zIndex: 50,
})}
>
{subtitle.description}
<Tooltip.Arrow
className={css({
fill: 'gray.900',
})}
/>
</Tooltip.Content>
</Tooltip.Portal>
</Tooltip.Root>
</Link>
) : (
<div />
)}
<div className={hstack({ gap: '6', alignItems: 'center' })}>
{/* Navigation Links */}
<nav className={hstack({ gap: '4' })}>
<NavLink href="/create" currentPath={pathname}>
Create
</NavLink>
<NavLink href="/guide" currentPath={pathname}>
Guide
</NavLink>
<NavLink href="/games" currentPath={pathname}>
Games
</NavLink>
</nav>
<div className={hstack({ gap: '6', alignItems: 'center' })}>
{/* Navigation Links */}
<nav className={hstack({ gap: '4' })}>
<NavLink href="/create" currentPath={pathname} isTransparent={isTransparent}>
Create
</NavLink>
<NavLink href="/guide" currentPath={pathname} isTransparent={isTransparent}>
Guide
</NavLink>
<NavLink href="/games" currentPath={pathname} isTransparent={isTransparent}>
Games
</NavLink>
</nav>
{/* Abacus Style Dropdown */}
<AbacusDisplayDropdown isFullscreen={false} />
{/* Abacus Style Dropdown */}
<AbacusDisplayDropdown isFullscreen={false} />
</div>
</div>
</div>
</div>
</header>
</header>
{/* Keyframes for fade-in animation */}
<style
dangerouslySetInnerHTML={{
__html: `
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-5px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
`,
}}
/>
</Tooltip.Provider>
)
}
@@ -587,10 +705,12 @@ function NavLink({
href,
currentPath,
children,
isTransparent,
}: {
href: string
currentPath: string | null
children: React.ReactNode
isTransparent?: boolean
}) {
const isActive = currentPath === href || (href !== '/' && currentPath?.startsWith(href))
@@ -604,8 +724,20 @@ function NavLink({
minW: { base: '44px', md: 'auto' },
fontSize: 'sm',
fontWeight: 'medium',
color: isActive ? 'brand.700' : 'gray.600',
bg: isActive ? 'brand.50' : 'transparent',
color: isTransparent
? isActive
? 'white'
: 'rgba(255, 255, 255, 0.8)'
: isActive
? 'brand.700'
: 'gray.600',
bg: isTransparent
? isActive
? 'rgba(255, 255, 255, 0.15)'
: 'transparent'
: isActive
? 'brand.50'
: 'transparent',
rounded: 'lg',
transition: 'all',
textDecoration: 'none',
@@ -613,8 +745,8 @@ function NavLink({
alignItems: 'center',
justifyContent: 'center',
_hover: {
color: isActive ? 'brand.800' : 'gray.900',
bg: isActive ? 'brand.100' : 'gray.50',
color: isTransparent ? 'white' : isActive ? 'brand.800' : 'gray.900',
bg: isTransparent ? 'rgba(255, 255, 255, 0.2)' : isActive ? 'brand.100' : 'gray.50',
},
})}
>

View File

@@ -0,0 +1,189 @@
'use client'
import { useEffect, useRef } from 'react'
import { AbacusReact, useAbacusConfig } from '@soroban/abacus-react'
import { css } from '../../styled-system/css'
import { useHomeHero } from '../contexts/HomeHeroContext'
export function HeroAbacus() {
const {
subtitle,
abacusValue,
setAbacusValue,
setIsHeroVisible,
isAbacusLoaded,
isSubtitleLoaded,
} = useHomeHero()
const appConfig = useAbacusConfig()
const heroRef = useRef<HTMLDivElement>(null)
// Styling for structural elements (solid, no translucency)
const structuralStyles = {
columnPosts: {
fill: 'rgb(255, 255, 255)',
stroke: 'rgb(200, 200, 200)',
strokeWidth: 2,
},
reckoningBar: {
fill: 'rgb(255, 255, 255)',
stroke: 'rgb(200, 200, 200)',
strokeWidth: 3,
},
}
// Detect when hero scrolls out of view
useEffect(() => {
if (!heroRef.current) return
const observer = new IntersectionObserver(
([entry]) => {
// Hero is visible if more than 20% is in viewport
setIsHeroVisible(entry.intersectionRatio > 0.2)
},
{
threshold: [0, 0.2, 0.5, 1],
}
)
observer.observe(heroRef.current)
return () => observer.disconnect()
}, [setIsHeroVisible])
return (
<div
ref={heroRef}
className={css({
height: '100vh',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'space-between',
bg: 'gray.900',
position: 'relative',
overflow: 'hidden',
px: '4',
py: '12',
})}
>
{/* Background pattern */}
<div
className={css({
position: 'absolute',
inset: 0,
opacity: 0.1,
backgroundImage:
'radial-gradient(circle at 2px 2px, rgba(255, 255, 255, 0.15) 1px, transparent 0)',
backgroundSize: '40px 40px',
})}
/>
{/* Title and Subtitle Section - DIRECT CHILD */}
<div
className={css({
position: 'relative',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: '2',
zIndex: 10,
})}
>
<h1
className={css({
fontSize: { base: '4xl', md: '6xl', lg: '7xl' },
fontWeight: 'bold',
background: 'linear-gradient(135deg, #fbbf24 0%, #f59e0b 50%, #fbbf24 100%)',
backgroundClip: 'text',
color: 'transparent',
})}
>
Abaci One
</h1>
<p
className={css({
fontSize: { base: 'xl', md: '2xl' },
fontWeight: 'medium',
color: 'purple.300',
fontStyle: 'italic',
marginBottom: '8',
opacity: isSubtitleLoaded ? 1 : 0,
transition: 'opacity 0.5s ease-in-out',
})}
>
{subtitle.text}
</p>
</div>
{/* Large Interactive Abacus - DIRECT CHILD */}
<div
className={css({
position: 'relative',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flex: '1',
width: '100%',
zIndex: 10,
opacity: isAbacusLoaded ? 1 : 0,
transition: 'opacity 0.5s ease-in-out',
})}
>
<div
className={css({
transform: { base: 'scale(2)', md: 'scale(3)', lg: 'scale(4)' },
transformOrigin: 'center center',
transition: 'all 0.5s cubic-bezier(0.4, 0, 0.2, 1)',
})}
>
<AbacusReact
value={abacusValue}
columns={4}
beadShape={appConfig.beadShape}
showNumbers={true}
interactive={true}
animated={true}
customStyles={structuralStyles}
onValueChange={setAbacusValue}
/>
</div>
</div>
{/* Subtle hint to scroll - DIRECT CHILD */}
<div
className={css({
position: 'relative',
fontSize: 'sm',
color: 'gray.400',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: '2',
animation: 'bounce 2s ease-in-out infinite',
zIndex: 10,
})}
>
<span>Scroll to explore</span>
<span></span>
</div>
{/* Keyframes for bounce animation */}
<style
dangerouslySetInnerHTML={{
__html: `
@keyframes bounce {
0%, 100% {
transform: translateY(0);
opacity: 0.7;
}
50% {
transform: translateY(-10px);
opacity: 1;
}
}
`,
}}
/>
</div>
)
}

View File

@@ -217,6 +217,7 @@ interface TutorialPlayerProps {
showDebugPanel?: boolean
hideNavigation?: boolean
hideTooltip?: boolean
silentErrors?: boolean
abacusColumns?: number
theme?: 'light' | 'dark'
onStepChange?: (stepIndex: number, step: TutorialStep) => void
@@ -233,6 +234,7 @@ function TutorialPlayerContent({
showDebugPanel = false,
hideNavigation = false,
hideTooltip = false,
silentErrors = false,
abacusColumns = 5,
theme = 'light',
onStepChange,
@@ -638,7 +640,7 @@ function TutorialPlayerContent({
maxWidth: '200px',
minWidth: '150px',
wordBreak: 'break-word',
zIndex: 1000,
zIndex: 50,
opacity: 0.95,
transition: 'all 0.3s ease',
transform: showCelebration ? 'scale(1.05)' : 'scale(1)',
@@ -909,7 +911,7 @@ function TutorialPlayerContent({
)
})
if (!isCorrectBead) {
if (!isCorrectBead && !silentErrors) {
const errorMessage = "That's not the highlighted bead. Try clicking the highlighted bead."
dispatch({
type: 'SET_ERROR',

View File

@@ -0,0 +1,127 @@
'use client'
import type React from 'react'
import { createContext, useContext, useEffect, useMemo, useRef, useState } from 'react'
import type { Subtitle } from '../data/abaciOneSubtitles'
import { subtitles } from '../data/abaciOneSubtitles'
interface HomeHeroContextValue {
subtitle: Subtitle
abacusValue: number
setAbacusValue: (value: number) => void
isHeroVisible: boolean
setIsHeroVisible: (visible: boolean) => void
isAbacusLoaded: boolean
isSubtitleLoaded: boolean
}
const HomeHeroContext = createContext<HomeHeroContextValue | null>(null)
export { HomeHeroContext }
export function HomeHeroProvider({ children }: { children: React.ReactNode }) {
// Use first subtitle for SSR, then select random one on client mount
const [subtitle, setSubtitle] = useState<Subtitle>(subtitles[0])
const [isSubtitleLoaded, setIsSubtitleLoaded] = useState(false)
// Select random subtitle only on client side, persist per-session
useEffect(() => {
// Check if we have a stored subtitle index for this session
const storedIndex = sessionStorage.getItem('heroSubtitleIndex')
if (storedIndex !== null) {
// Use the stored subtitle index
const index = parseInt(storedIndex, 10)
if (!Number.isNaN(index) && index >= 0 && index < subtitles.length) {
setSubtitle(subtitles[index])
setIsSubtitleLoaded(true)
return
}
}
// Generate a new random index and store it
const randomIndex = Math.floor(Math.random() * subtitles.length)
sessionStorage.setItem('heroSubtitleIndex', randomIndex.toString())
setSubtitle(subtitles[randomIndex])
setIsSubtitleLoaded(true)
}, [])
// Shared abacus value - always start at 0 for SSR/hydration consistency
const [abacusValue, setAbacusValue] = useState(0)
const [isAbacusLoaded, setIsAbacusLoaded] = useState(false)
const isLoadingFromStorage = useRef(false)
// Load from sessionStorage after mount (client-only, no hydration mismatch)
useEffect(() => {
console.log('[HeroAbacus] Loading from sessionStorage...')
isLoadingFromStorage.current = true // Block saves during load
const saved = sessionStorage.getItem('heroAbacusValue')
console.log('[HeroAbacus] Saved value from storage:', saved)
if (saved) {
const parsedValue = parseInt(saved, 10)
console.log('[HeroAbacus] Parsed value:', parsedValue)
if (!Number.isNaN(parsedValue)) {
console.log('[HeroAbacus] Setting abacus value to:', parsedValue)
setAbacusValue(parsedValue)
}
} else {
console.log('[HeroAbacus] No saved value found, staying at 0')
}
// Use setTimeout to ensure the value has been set before we allow saves
setTimeout(() => {
isLoadingFromStorage.current = false
setIsAbacusLoaded(true)
console.log('[HeroAbacus] Load complete, allowing saves now and fading in')
}, 0)
}, [])
// Persist value to sessionStorage when it changes (but skip during load)
useEffect(() => {
console.log(
'[HeroAbacus] Save effect triggered. Value:',
abacusValue,
'isLoadingFromStorage:',
isLoadingFromStorage.current
)
if (!isLoadingFromStorage.current) {
console.log('[HeroAbacus] Saving to sessionStorage:', abacusValue)
sessionStorage.setItem('heroAbacusValue', abacusValue.toString())
console.log(
'[HeroAbacus] Saved successfully. Storage now contains:',
sessionStorage.getItem('heroAbacusValue')
)
} else {
console.log('[HeroAbacus] Skipping save (currently loading from storage)')
}
}, [abacusValue])
// Track hero visibility for nav branding
const [isHeroVisible, setIsHeroVisible] = useState(true)
const value = useMemo(
() => ({
subtitle,
abacusValue,
setAbacusValue,
isHeroVisible,
setIsHeroVisible,
isAbacusLoaded,
isSubtitleLoaded,
}),
[subtitle, abacusValue, isHeroVisible, isAbacusLoaded, isSubtitleLoaded]
)
return <HomeHeroContext.Provider value={value}>{children}</HomeHeroContext.Provider>
}
export function useHomeHero() {
const context = useContext(HomeHeroContext)
if (!context) {
throw new Error('useHomeHero must be used within HomeHeroProvider')
}
return context
}

View File

@@ -0,0 +1,97 @@
/**
* Abaci One subtitle options with descriptions
* Three-word rhyming subtitles for the main app navigation
*/
export interface Subtitle {
text: string
description: string
}
export const subtitles: Subtitle[] = [
{ text: 'Speed Bead Lead', description: 'blaze through bead races' },
{ text: 'Rod Mod Nod', description: 'tweak rod technique, approval earned' },
{ text: 'Grid Kid Lid', description: 'lock in neat grid habits' },
{ text: 'Count Mount Amount', description: 'stack up that number sense' },
{ text: 'Stack Track Tack', description: 'line up beads, lock in sums' },
{ text: 'Quick Flick Trick', description: 'rapid-fire bead tactics' },
{ text: 'Flash Dash Math', description: 'fly through numeric challenges' },
{ text: 'Slide Glide Pride', description: 'smooth soroban strokes' },
{ text: 'Shift Sift Gift', description: 'sort beads, reveal talent' },
{ text: 'Beat Seat Meet', description: 'compete head-to-head' },
{ text: 'Brain Train Gain', description: 'mental math muscle building' },
{ text: 'Flow Show Pro', description: 'demonstrate soroban mastery' },
{ text: 'Fast Blast Past', description: 'surpass speed limits' },
{ text: 'Snap Tap Map', description: 'chart your calculation path' },
{ text: 'Row Grow Know', description: 'advance through structured drills' },
{ text: 'Drill Skill Thrill', description: 'practice that excites' },
{ text: 'Think Link Sync', description: 'connect mind and beads' },
{ text: 'Boost Joust Roost', description: 'power up, compete, settle in' },
{ text: 'Add Grad Rad', description: 'level up addition awesomely' },
{ text: 'Sum Fun Run', description: 'enjoy the arithmetic sprint' },
{ text: 'Track Stack Pack', description: 'organize solutions systematically' },
{ text: 'Beat Neat Feat', description: 'clean victories, impressive wins' },
{ text: 'Math Path Wrath', description: 'dominate numeric challenges' },
{ text: 'Spark Mark Arc', description: 'ignite progress, track growth' },
{ text: 'Race Pace Ace', description: 'speed up, master it' },
{ text: 'Flex Hex Reflex', description: 'adapt calculations instantly' },
{ text: 'Glide Pride Stride', description: 'smooth confident progress' },
{ text: 'Flash Dash Smash', description: 'speed through, crush totals' },
{ text: 'Stack Attack Jack', description: 'aggressive bead strategies' },
{ text: 'Quick Pick Click', description: 'rapid bead selection' },
{ text: 'Snap Map Tap', description: 'visualize and execute' },
{ text: 'Mind Find Grind', description: 'discover mental endurance' },
{ text: 'Flip Skip Rip', description: 'fast transitions, tear through' },
{ text: 'Blend Trend Send', description: 'mix methods, share progress' },
{ text: 'Power Tower Hour', description: 'build skills intensively' },
{ text: 'Launch Staunch Haunch', description: 'start strong, stay firm' },
{ text: 'Rush Crush Hush', description: 'speed quietly dominates' },
{ text: 'Swipe Stripe Hype', description: 'sleek moves, excitement' },
{ text: 'Train Gain Sustain', description: 'build lasting ability' },
{ text: 'Frame Claim Flame', description: 'structure your fire' },
{ text: 'Streak Peak Tweak', description: 'hot runs, optimize performance' },
{ text: 'Edge Pledge Wedge', description: 'commit to precision' },
{ text: 'Pace Grace Space', description: 'rhythm, elegance, room to grow' },
{ text: 'Link Think Brink', description: 'connect at breakthrough edge' },
{ text: 'Quest Test Best', description: 'challenge yourself to excel' },
{ text: 'Drive Thrive Arrive', description: 'push hard, succeed, reach goals' },
{ text: 'Smart Start Chart', description: 'begin wisely, track progress' },
{ text: 'Boost Coast Toast', description: 'accelerate, cruise, celebrate' },
{ text: 'Spark Dark Embark', description: 'ignite before dawn journeys' },
{ text: 'Blaze Graze Amaze', description: 'burn through, touch lightly, wow' },
{ text: 'Shift Drift Gift', description: 'adapt smoothly, reveal talent' },
{ text: 'Zone Hone Own', description: 'focus, refine, claim mastery' },
{ text: 'Vault Halt Exalt', description: 'leap high, pause, celebrate' },
{ text: 'Peak Seek Streak', description: 'find heights, maintain momentum' },
{ text: 'Glow Show Grow', description: 'shine, display, expand' },
{ text: 'Scope Hope Rope', description: 'survey possibilities, climb up' },
{ text: 'Core Score More', description: 'fundamentals yield better results' },
{ text: 'Rank Bank Thank', description: 'earn status, save wins, appreciate' },
{ text: 'Merge Surge Verge', description: 'combine forces, power up, edge closer' },
{ text: 'Bold Gold Hold', description: 'brave attempts, prize rewards, maintain' },
{ text: 'Rise Prize Wise', description: 'ascend, win, learn' },
{ text: 'Move Groove Prove', description: 'act, find rhythm, demonstrate' },
{ text: 'Trust Thrust Adjust', description: 'believe, push, refine' },
{ text: 'Beam Dream Team', description: 'radiate, aspire, collaborate' },
{ text: 'Spin Win Grin', description: 'rotate beads, succeed, smile' },
{ text: 'String Ring Bring', description: 'connect, cycle, deliver' },
{ text: 'Clear Gear Steer', description: 'focus, equip, direct' },
{ text: 'Path Math Aftermath', description: 'route, calculate, results' },
{ text: 'Play Slay Day', description: 'engage, dominate, own it' },
{ text: 'Code Mode Road', description: 'pattern, style, journey' },
{ text: 'Craft Draft Shaft', description: 'build, sketch, core structure' },
{ text: 'Light Might Fight', description: 'illuminate, empower, compete' },
{ text: 'Stream Dream Extreme', description: 'flow, envision, push limits' },
{ text: 'Claim Frame Aim', description: 'assert, structure, target' },
{ text: 'Chart Smart Start', description: 'map, intelligent, begin' },
{ text: 'Bright Flight Height', description: 'brilliant, soar, elevation' },
]
/**
* Get a random subtitle from the list
* Uses current timestamp as seed for variety across sessions
*/
export function getRandomSubtitle(): Subtitle {
const index = Math.floor(Math.random() * subtitles.length)
return subtitles[index]
}

View File

@@ -0,0 +1,123 @@
/**
* Detailed requirements for each Kyu level in the Soroban certification system
* Source: shuzan.jp
*
* Note: Stored verbatim from source. Display formatting/translation happens in the UI layer.
*/
export const kyuLevelDetails = {
'10-kyu': `Add/Sub: 2-digit, 5口, 10字
×: 実+法 = 3 digits (20 problems)
Time: 20 min; Pass ≥ 60/200.
shuzan.jp`,
'9-kyu': `Add/Sub: 2-digit, 5口, 10字
×: 実+法 = 3 digits (20)
Time: 20 min; Pass ≥ 120/200. (If only one part clears, it's treated as 10-kyu per federation notes.)
shuzan.jp`,
'8-kyu': `Add/Sub: 2-digit, 8口, 16字
×: 実+法 = 4 digits (10)
÷: 法+商 = 3 digits (10)
Time: 20 min; Pass ≥ 120/200.
shuzan.jp`,
'7-kyu': `Add/Sub: 2-digit, 10口, 20字
×: 実+法 = 4 digits (10)
÷: 法+商 = 4 digits (10)
Time: 20 min; Pass ≥ 120/200.
shuzan.jp`,
'6-kyu': `Add/Sub: 10口, 30字
×: 実+法 = 5 digits (20)
÷: 法+商 = 4 digits (20)
Time: 30 min; Pass ≥ 210/300.
shuzan.jp`,
'5-kyu': `Add/Sub: 10口, 40字
×: 実+法 = 6 digits (20)
÷: 法+商 = 5 digits (20)
Time: 30 min; Pass ≥ 210/300.
shuzan.jp`,
'4-kyu': `Add/Sub: 10口, 50字
×: 実+法 = 7 digits (20)
÷: 法+商 = 6 digits (20)
Time: 30 min; Pass ≥ 210/300.
shuzan.jp`,
'Pre-3-kyu': `Add/Sub: 10口, 50字 ×5題 and 10口, 60字 ×5題 (total 10)
×: 実+法 = 7 digits (20)
÷: 法+商 = 6 digits (20)
Time: 30 min; Pass ≥ 240/300.
shuzan.jp`,
'3-kyu': `Add/Sub: 10口, 60字
×: 実+法 = 7 digits (20)
÷: 法+商 = 6 digits (20)
Time: 30 min; Pass ≥ 240/300.
shuzan.jp`,
'Pre-2-kyu': `Add/Sub: 10口, 70字
×: 実+法 = 8 digits (20)
÷: 法+商 = 7 digits (20)
Time: 30 min; Pass ≥ 240/300.
shuzan.jp`,
'2-kyu': `Add/Sub: 10口, 80字
×: 実+法 = 9 digits (20)
÷: 法+商 = 8 digits (20)
Time: 30 min; Pass ≥ 240/300.
shuzan.jp`,
'Pre-1-kyu': `Add/Sub: 10口, 90字
×: 実+法 = 10 digits (20)
÷: 法+商 = 9 digits (20)
Time: 30 min; Pass ≥ 240/300.
shuzan.jp`,
'1-kyu': `Add/Sub: 10口, 100字
×: 実+法 = 11 digits (20)
÷: 法+商 = 10 digits (20)
Time: 30 min; Pass ≥ 240/300.
shuzan.jp`,
} as const
export type KyuLevel = keyof typeof kyuLevelDetails

View File

@@ -1,6 +1,6 @@
{
"name": "soroban-monorepo",
"version": "4.20.2",
"version": "4.48.2",
"private": true,
"description": "Beautiful Soroban Flashcard Generator - Monorepo",
"workspaces": [

View File

@@ -1,3 +1,305 @@
# [2.1.0](https://github.com/antialias/soroban-abacus-flashcards/compare/abacus-react-v2.0.0...abacus-react-v2.1.0) (2025-10-20)
### Bug Fixes
* **levels:** add fixed height to entire level display pane ([200b26c](https://github.com/antialias/soroban-abacus-flashcards/commit/200b26c2cd35d1d637ede9dcfc3dbbc7f3f19320))
* **levels:** increase container height to prevent abacus clipping ([cd5c15a](https://github.com/antialias/soroban-abacus-flashcards/commit/cd5c15aeb260c568fe7ad9b6a4f51c4d6498b2b8))
* **levels:** only animate abacus, not container with background/border ([c80477d](https://github.com/antialias/soroban-abacus-flashcards/commit/c80477d24877ddada5f3f4405abbf05e1d753b5d))
* **levels:** reduce Dan scale and container height to prevent clipping ([563136f](https://github.com/antialias/soroban-abacus-flashcards/commit/563136fb79fa10b2af3a119bf0f861e3b0812b2e))
* **levels:** reduce max scale factor to allow more compact container ([ead9ee9](https://github.com/antialias/soroban-abacus-flashcards/commit/ead9ee9589aa4d7376e9385da5da53a6b444858a))
* **levels:** reduce scale factor variation to minimize margin differences ([abb647c](https://github.com/antialias/soroban-abacus-flashcards/commit/abb647ce40b8f9d0c8268ab18c139324ae3195c5))
* **levels:** revert delayed column change, keep overflow hidden ([22f00f5](https://github.com/antialias/soroban-abacus-flashcards/commit/22f00f59f5facc36a846408dcd196ec54ea676b1))
* **levels:** stabilize slider position and prevent abacus clipping ([09004dc](https://github.com/antialias/soroban-abacus-flashcards/commit/09004dc2c055031ee2f71c964ceee6f7b1d42ecd))
### Features
* **abacus-react:** export StandaloneBead component wired to AbacusDisplayContext ([0146ce1](https://github.com/antialias/soroban-abacus-flashcards/commit/0146ce1e67da27a24cbaa8338ba6a1a6befd6bd3))
* **levels:** add hover interaction and smooth React Spring transitions ([fd2b633](https://github.com/antialias/soroban-abacus-flashcards/commit/fd2b6338a84c3bbc683eff216a8da3b155749f0f))
* **levels:** redesign slider with abacus-themed beads ([f3dce84](https://github.com/antialias/soroban-abacus-flashcards/commit/f3dce84532fa706e4ec9551facde2055a060ee13))
* **levels:** replace slider thumb with diamond-shaped abacus beads ([0fbde53](https://github.com/antialias/soroban-abacus-flashcards/commit/0fbde53039d3ea000c6a3be492b733479e7bf47c))
# [2.0.0](https://github.com/antialias/soroban-abacus-flashcards/compare/abacus-react-v1.8.0...abacus-react-v2.0.0) (2025-10-20)
### Bug Fixes
* add dark color for abacus numerals ([73ff32c](https://github.com/antialias/soroban-abacus-flashcards/commit/73ff32c2432beb62710e57aa8b3b4793eca43fda)), closes [#1f2937](https://github.com/antialias/soroban-abacus-flashcards/issues/1f2937)
* add POST handler for join requests API endpoint ([d3e5cdf](https://github.com/antialias/soroban-abacus-flashcards/commit/d3e5cdfc54f2749f27c6f8b8db854a8d0b6029f8))
* add Typst to Docker image for flashcard generation ([d9a7694](https://github.com/antialias/soroban-abacus-flashcards/commit/d9a769403187bf70fb069be7ffe77417a62271a5))
* allow join with pending invitation for restricted rooms ([85b2cf9](https://github.com/antialias/soroban-abacus-flashcards/commit/85b2cf98167ccf632ab634a94eb436e1eb584614))
* allow password retry when joining via share link ([e469363](https://github.com/antialias/soroban-abacus-flashcards/commit/e469363699071610a35e0b5c507d0e15e29daa44))
* **api:** add 'math-sprint' to settings endpoint validation ([d790e5e](https://github.com/antialias/soroban-abacus-flashcards/commit/d790e5e278f81686077dbe3ef4adca49574ae434)), closes [#1](https://github.com/antialias/soroban-abacus-flashcards/issues/1)
* **api:** include members and memberPlayers in room creation response ([8320d9e](https://github.com/antialias/soroban-abacus-flashcards/commit/8320d9e730e2b9964e509847dfa504a78b721b5a))
* **arcade-rooms:** navigate to invite link after room creation ([1922b21](https://github.com/antialias/soroban-abacus-flashcards/commit/1922b2122bb1bc4aeada7526d8c46aa89024bb00))
* **arcade:** add defensive checks and update test fixtures ([a93d981](https://github.com/antialias/soroban-abacus-flashcards/commit/a93d981d1ab3abed019b28cebe87525191313cc7))
* **arcade:** add host-only game selection with clear messaging ([22df1b0](https://github.com/antialias/soroban-abacus-flashcards/commit/22df1b0b661efe69fac1a6bd716531c904757412))
* **arcade:** add host-only game selection with clear messaging ([c0680ca](https://github.com/antialias/soroban-abacus-flashcards/commit/c0680cad0fa26af0933e93a06c50317bf443cc7d))
* **arcade:** add Number Guesser to game config helpers ([7d1a351](https://github.com/antialias/soroban-abacus-flashcards/commit/7d1a351ed6a1442ae34f6b75d46039bfa77a921b))
* **arcade:** allow room creator to rejoin restricted/approval rooms ([654ba19](https://github.com/antialias/soroban-abacus-flashcards/commit/654ba19ccca595d34ad205c036c18afb99a494c7))
* **arcade:** delete old session when room game changes ([98a3a25](https://github.com/antialias/soroban-abacus-flashcards/commit/98a3a2573db51899c41ba02796895d676c4e16ef))
* **arcade:** implement settings persistence for matching game ([08fe432](https://github.com/antialias/soroban-abacus-flashcards/commit/08fe4326a6a7c484b9058a241f4ff79b3fb5125f))
* **arcade:** only notify room creator of join requests ([bc571e3](https://github.com/antialias/soroban-abacus-flashcards/commit/bc571e3d0d11fe4142680132d551e25ca626d950))
* **arcade:** preserve game settings when returning to game selection ([0ee7739](https://github.com/antialias/soroban-abacus-flashcards/commit/0ee7739091d60580d2f98cfe288b8586b03348f3))
* **arcade:** preserve gameConfig when switching games ([2273c71](https://github.com/antialias/soroban-abacus-flashcards/commit/2273c71a872a5122d0b2023835fe30640106048e))
* **arcade:** prevent empty update in settings API when only gameConfig changes ([ffb626f](https://github.com/antialias/soroban-abacus-flashcards/commit/ffb626f4038fd32d0f40dba8d83ae4d881d698d0))
* **arcade:** prevent gameConfig from being overwritten when switching games ([a89d3a9](https://github.com/antialias/soroban-abacus-flashcards/commit/a89d3a970137471e2652de992c45370dbb97416d))
* **arcade:** prevent server-side loading of React components ([784793b](https://github.com/antialias/soroban-abacus-flashcards/commit/784793ba244731edf45391da44588a978b137abe))
* **arcade:** read nested gameConfig correctly when creating sessions ([94ef392](https://github.com/antialias/soroban-abacus-flashcards/commit/94ef39234d362b82e032cb69d3561b9fcb436eaf))
* **arcade:** remove broken query param from game URLs ([87631af](https://github.com/antialias/soroban-abacus-flashcards/commit/87631af6788bd7b42e671374e55ec0ad8435900c))
* **arcade:** remove legacy master-organizer placeholder ([76d207e](https://github.com/antialias/soroban-abacus-flashcards/commit/76d207e2e5244f84bc0d76fe3d753034f1991228))
* **arcade:** resolve TypeScript errors in game config helpers ([04c9944](https://github.com/antialias/soroban-abacus-flashcards/commit/04c9944f2ed1025f5a4ece61761889edd08cc60d))
* **build:** resolve Docker build failures preventing deployment ([7801dbb](https://github.com/antialias/soroban-abacus-flashcards/commit/7801dbb25fb0a33429c70f11294264f7238ce7a4))
* **card-sorting:** center AbacusReact SVGs in card tiles ([26edec1](https://github.com/antialias/soroban-abacus-flashcards/commit/26edec1bbf038264405ec9d161edcd18f67a6fc6))
* **card-sorting:** faithfully port UI/UX from Python original ([c92076f](https://github.com/antialias/soroban-abacus-flashcards/commit/c92076f232930aa12d9a0230fa745b73b5cc04d9)), closes [#2c5f76](https://github.com/antialias/soroban-abacus-flashcards/issues/2c5f76) [#1976d2](https://github.com/antialias/soroban-abacus-flashcards/issues/1976d2)
* **card-sorting:** increase card tile sizes to contain abacuses ([d2a3b7a](https://github.com/antialias/soroban-abacus-flashcards/commit/d2a3b7ae2e3f6819b8d9ace32be22f04f748d1bc))
* **card-sorting:** increase SVG size to fill card containers ([cf9d893](https://github.com/antialias/soroban-abacus-flashcards/commit/cf9d893f3fdbef6e91cd0ba283d602b9215569f1))
* **card-sorting:** match game selector background to other games ([db62519](https://github.com/antialias/soroban-abacus-flashcards/commit/db62519f9beb0b4bc6120e1fd5ec251cfde5c3c1)), closes [#ccfbf1](https://github.com/antialias/soroban-abacus-flashcards/issues/ccfbf1) [#99f6e4](https://github.com/antialias/soroban-abacus-flashcards/issues/99f6e4)
* **card-sorting:** match Python card layout with flex wrap ([9679d68](https://github.com/antialias/soroban-abacus-flashcards/commit/9679d68154ac8b6a2f905ec7d17a34b39bc00237))
* **card-sorting:** position slots flow horizontally with wrap ([e14ffe4](https://github.com/antialias/soroban-abacus-flashcards/commit/e14ffe44d66d0c97bc0cc4e0c255698e88ce723a))
* **card-sorting:** use blue gradient matching other game cards ([bdb84f5](https://github.com/antialias/soroban-abacus-flashcards/commit/bdb84f5d909542060fa886a83a5af62c4a785a98))
* clear hover state in CLEAR_MISMATCH for clean turn transitions ([43f7c92](https://github.com/antialias/soroban-abacus-flashcards/commit/43f7c92f6d61616e18439c995dc4a4848e233520))
* clear hover state on turn changes and game transitions ([6fd425c](https://github.com/antialias/soroban-abacus-flashcards/commit/6fd425ce85ddbf5e0125f757dc9886915fb6f749))
* **complement-race:** add missing AI commentary cooldown updates ([357aa30](https://github.com/antialias/soroban-abacus-flashcards/commit/357aa30618f80d659ae515f94b7b9254bb458910))
* **complement-race:** add missing useEffect import ([3054130](https://github.com/antialias/soroban-abacus-flashcards/commit/30541304dd0f0801860dd62967f7f7cae717bcdd))
* **complement-race:** add missing useRef import ([d43829a](https://github.com/antialias/soroban-abacus-flashcards/commit/d43829ad48f7ee879a46879f5e6ac1256db1f564))
* **complement-race:** add pressure decay system and improve logging ([66992e8](https://github.com/antialias/soroban-abacus-flashcards/commit/66992e877065a42d00379ef8fae0a6e252b0ffcb))
* **complement-race:** balance AI speeds to match original implementation ([054f0c0](https://github.com/antialias/soroban-abacus-flashcards/commit/054f0c0d235dc2b0042a0f6af48840d23a4c5ff8))
* **complement-race:** clear input state on question transitions ([5872030](https://github.com/antialias/soroban-abacus-flashcards/commit/587203056a1e1692348805eb0de909d81d16e158))
* **complement-race:** correct passenger boarding to use multiplayer fields ([7ed1b94](https://github.com/antialias/soroban-abacus-flashcards/commit/7ed1b94b8fa620cb4f64ba43e160ef511704f3ce))
* **complement-race:** counter-flip AI speech bubbles to make text readable ([07d5607](https://github.com/antialias/soroban-abacus-flashcards/commit/07d5607218aee03e813eceff5d161a7838d66bcb))
* **complement-race:** flip AI racers to face right in practice mode ([ebfff1a](https://github.com/antialias/soroban-abacus-flashcards/commit/ebfff1a62fd104d531a8158345c8c012ec8a55d3))
* **complement-race:** flip player avatar to face right in practice mode ([fa6b3b6](https://github.com/antialias/soroban-abacus-flashcards/commit/fa6b3b69d5a4a7eb70f8c18fc8c122c54c4d504a))
* **complement-race:** implement client-side momentum with continuous decay for smooth train movement ([ea19ff9](https://github.com/antialias/soroban-abacus-flashcards/commit/ea19ff918bc70ad3eb0339e18dbd32195f34816e))
* **complement-race:** improve AI speech bubble positioning ([6e436db](https://github.com/antialias/soroban-abacus-flashcards/commit/6e436db5e709d944ebffed6936ea1f8e4bd2e19e))
* **complement-race:** reduce initial momentum from 50 to 10 to prevent train sailing past first station ([5f146b0](https://github.com/antialias/soroban-abacus-flashcards/commit/5f146b0daf74d54e1c7b9a57d3a2f37e73849ff2))
* **complement-race:** remove dual game loop conflict preventing route progression ([84d42e2](https://github.com/antialias/soroban-abacus-flashcards/commit/84d42e22ac0cdd25e87e45dc698029ad7ed78559))
* **complement-race:** resolve TypeScript errors in state adapter ([59abcca](https://github.com/antialias/soroban-abacus-flashcards/commit/59abcca4c4192ca28944fa1fa366791d557c1c27))
* **complement-race:** restore smooth train movement with client-side game loop ([46a80cb](https://github.com/antialias/soroban-abacus-flashcards/commit/46a80cbcc8ec39224d4edaf540da25611d48fbdd))
* **complement-race:** show new passengers when route changes ([ec1c8ed](https://github.com/antialias/soroban-abacus-flashcards/commit/ec1c8ed263844f56477c1f709041339b42b48f4e))
* **complement-race:** track physical car indices to prevent boarding issues ([53bbae8](https://github.com/antialias/soroban-abacus-flashcards/commit/53bbae84af7317d5e12109db2054cc70ca5bea27))
* **complement-race:** track previous position to detect route threshold crossing ([a6c20aa](https://github.com/antialias/soroban-abacus-flashcards/commit/a6c20aab3b245d9893808d188d16a35ab80cfca9))
* **complement-race:** train now moves in sprint mode ([54b46e7](https://github.com/antialias/soroban-abacus-flashcards/commit/54b46e771e654721e7fabb1f45ecd45daf8e447f))
* **complement-race:** update passenger display when state changes ([5116364](https://github.com/antialias/soroban-abacus-flashcards/commit/511636400c19776b58c6bddf8f7c9cc398a05236))
* **complement-race:** use active local players pattern from navbar ([71cdc34](https://github.com/antialias/soroban-abacus-flashcards/commit/71cdc342c97ca53b5e7e4202d4d344199e8ddd98))
* **complement-race:** use local player emoji instead of first active player ([76eb051](https://github.com/antialias/soroban-abacus-flashcards/commit/76eb0517c202d1b9160b49dec0b99ff4972daff2))
* correct AbacusReact API usage and add structural styling ([247377f](https://github.com/antialias/soroban-abacus-flashcards/commit/247377fca35ee3433e02ad594ecc1c4f391f0143)), closes [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24) [#a78](https://github.com/antialias/soroban-abacus-flashcards/issues/a78)
* create arcade sessions on room join to enable config changes ([c29501f](https://github.com/antialias/soroban-abacus-flashcards/commit/c29501f6663cb6063f2ddef8b3fdb14c31927639))
* **db:** add 'math-sprint' to database schema enums ([7b112a9](https://github.com/antialias/soroban-abacus-flashcards/commit/7b112a98babe782d4c254ef18a0295e7cbf8fefa)), closes [#1](https://github.com/antialias/soroban-abacus-flashcards/issues/1)
* **deployment:** pass git info to Docker build for deployment info modal ([4b04e43](https://github.com/antialias/soroban-abacus-flashcards/commit/4b04e43ff8c9e9f239d7f5e306aab338b535296f))
* **docker:** add packages/templates for Typst flashcard generation ([1417722](https://github.com/antialias/soroban-abacus-flashcards/commit/14177224380b8c37413123bee344c9b762055a15))
* **docker:** add qpdf for PDF linearization and validation ([c92ff39](https://github.com/antialias/soroban-abacus-flashcards/commit/c92ff3971c853e4e55ccd632ff3ee292fcce8315))
* **docker:** bypass PEP 668 externally-managed-environment error ([bb59c61](https://github.com/antialias/soroban-abacus-flashcards/commit/bb59c61638e60b0678043e954e044d9390f88e7f))
* **docker:** copy core package with Python scripts to production image ([33e9ad2](https://github.com/antialias/soroban-abacus-flashcards/commit/33e9ad2f79b591f1c5ee57a6691e1bcf48420859))
* **docker:** include Panda CSS styled-system in production image ([57fabff](https://github.com/antialias/soroban-abacus-flashcards/commit/57fabffe605d953b4a4d7e05032401cbf1ab2d14))
* **docker:** install py3-pip for Python dependency installation ([0f55909](https://github.com/antialias/soroban-abacus-flashcards/commit/0f55909533414bdc07f113b93bb8bfa21367959b))
* **docker:** install Python dependencies for flashcard generation ([c9b7e92](https://github.com/antialias/soroban-abacus-flashcards/commit/c9b7e92f39ee7aa7f13606c2836763144df102e7))
* **docker:** remove reference to deleted @soroban/client package ([2953ef8](https://github.com/antialias/soroban-abacus-flashcards/commit/2953ef8917f7b13f6eb562eb7d58d14179a718da))
* exclude dist from TypeScript compilation and add missing type import ([b7f1d5a](https://github.com/antialias/soroban-abacus-flashcards/commit/b7f1d5a5696888bb4fbf6d5da14ca333de0f0167))
* hide hover avatar for current user's own player ([dba42b5](https://github.com/antialias/soroban-abacus-flashcards/commit/dba42b59257f2422ec8f31a46c222393fcc157d4))
* **homepage:** adjust mini abacus container height ([c4066d6](https://github.com/antialias/soroban-abacus-flashcards/commit/c4066d687925bbe7737ebfeefdada7365ff97c6c))
* **homepage:** correct positioning of progression arrows in Your Journey section ([3fff9ef](https://github.com/antialias/soroban-abacus-flashcards/commit/3fff9ef140bf1f462042f8319ed6c5e2a376e4ba))
* **homepage:** fix MiniAbacus runtime error and improve sizing ([1fa0df8](https://github.com/antialias/soroban-abacus-flashcards/commit/1fa0df85f7d3988cbc61701d89476419ccf0a13c))
* **homepage:** improve text contrast in Your Journey section ([24d1200](https://github.com/antialias/soroban-abacus-flashcards/commit/24d120004dccecc1ce2f08c1b73eec902868fb23))
* **homepage:** use correct AbacusReact API and fix clipping/styling issues ([1432afd](https://github.com/antialias/soroban-abacus-flashcards/commit/1432afd6e6bd547bd0da76dbeea1c2b71244826f))
* **homepage:** use direct conditionals for mini abacus padding ([38ef16a](https://github.com/antialias/soroban-abacus-flashcards/commit/38ef16a8f91f8ab4ad0d717b0321e2002636fafb))
* **homepage:** use explicit RGBA colors for Your Journey text ([9c51cc9](https://github.com/antialias/soroban-abacus-flashcards/commit/9c51cc94eec4efcab9c0b9d1190f5b79c0c7d365))
* **homepage:** use inline styles for journey level colors ([5d85e89](https://github.com/antialias/soroban-abacus-flashcards/commit/5d85e898d65d44d8d09bee952fad44b5a9c0cd20)), closes [#4ade80](https://github.com/antialias/soroban-abacus-flashcards/issues/4ade80) [#60a5](https://github.com/antialias/soroban-abacus-flashcards/issues/60a5) [#a78](https://github.com/antialias/soroban-abacus-flashcards/issues/a78) [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24)
* **homepage:** use inline styles for Your Journey text contrast ([8e51390](https://github.com/antialias/soroban-abacus-flashcards/commit/8e5139001818d7013e1b2654ac707f7429316d58)), closes [#e5e7](https://github.com/antialias/soroban-abacus-flashcards/issues/e5e7) [#e5e7](https://github.com/antialias/soroban-abacus-flashcards/issues/e5e7) [#9ca3](https://github.com/antialias/soroban-abacus-flashcards/issues/9ca3) [#d1d5](https://github.com/antialias/soroban-abacus-flashcards/issues/d1d5)
* **home:** use Panda CSS token() for dynamic colors and center arrows properly ([d52ba63](https://github.com/antialias/soroban-abacus-flashcards/commit/d52ba6373a4577655dc1e5f5ff4926af7f7d96c3))
* improve authorization error handling and add missing decline invitation endpoint ([97669ad](https://github.com/antialias/soroban-abacus-flashcards/commit/97669ad084b077cbf6f33b570710016ba666cdb6))
* improve join request approval error handling with actionable messages ([57bf846](https://github.com/antialias/soroban-abacus-flashcards/commit/57bf8460c8ecff374355bfb93f4b06dfbb148273))
* improve kicked modal message for retired room ejections ([f865ce1](https://github.com/antialias/soroban-abacus-flashcards/commit/f865ce16ecf7648e41549795c8137f4fc33e34ac))
* join user socket channel to receive approval notifications ([7d08fdd](https://github.com/antialias/soroban-abacus-flashcards/commit/7d08fdd90643920857eda09998ac01afbae74154))
* **levels:** use correct AbacusReact API with direct props ([892b377](https://github.com/antialias/soroban-abacus-flashcards/commit/892b377eb3bbd555dd2566bf58e946e9faa7b9f6))
* **levels:** use correct dark mode styling from homepage + docs update ([c38767f](https://github.com/antialias/soroban-abacus-flashcards/commit/c38767f4d399fa2caa5cd4e0185689d0207fbdaf))
* **matching:** add settings persistence to matching game ([00dcb87](https://github.com/antialias/soroban-abacus-flashcards/commit/00dcb872b7e70bdb7de301b56fe42195e6ee923f))
* **matching:** apply turn indicators to arcade version too ([e6f96a8](https://github.com/antialias/soroban-abacus-flashcards/commit/e6f96a8b992c15f868ac5b1c1ac36b32caf433ed))
* **matching:** make MemoryGrid generic to support different card types ([dcda826](https://github.com/antialias/soroban-abacus-flashcards/commit/dcda826b9a7cab6614638f8661f288e9fa010324))
* **matching:** only apply turn indicator when game is active ([cb4c061](https://github.com/antialias/soroban-abacus-flashcards/commit/cb4c061d11433799a0091f4a958371ff7cef7a00))
* **matching:** replace mismatch banner with card shake animation ([804096f](https://github.com/antialias/soroban-abacus-flashcards/commit/804096fd8a0709750114ab01a1015f9b5fc28b63))
* **matching:** use UUID instead of numeric index for scores ([5036cb0](https://github.com/antialias/soroban-abacus-flashcards/commit/5036cb00b6eff91cfa52b5babb7e5a91ff7e18b3))
* **math-sprint:** remove unused import and autoFocus attribute ([51593eb](https://github.com/antialias/soroban-abacus-flashcards/commit/51593eb44f93e369d6a773ee80e5f5cf50f3be67))
* **memory-quiz:** fix playMode persistence by updating validator ([de0efd5](https://github.com/antialias/soroban-abacus-flashcards/commit/de0efd59321ec779cddb900724035884290419b7))
* **memory-quiz:** persist playMode setting across game switches ([487ca7f](https://github.com/antialias/soroban-abacus-flashcards/commit/487ca7fba62e370c85bc3779ca8a96eb2c2cc3e3))
* **memory-quiz:** prevent duplicate card processing from optimistic updates ([51676fc](https://github.com/antialias/soroban-abacus-flashcards/commit/51676fc15f5bc15cdb43393d3e66f7c5a0667868))
* **memory-quiz:** prevent input lag during rapid typing in room mode ([b45139b](https://github.com/antialias/soroban-abacus-flashcards/commit/b45139b588d0ab6df4d6c1003c1b65b634e2b041))
* **memory-quiz:** scope game settings by game name for proper persistence ([3dfe54f](https://github.com/antialias/soroban-abacus-flashcards/commit/3dfe54f1cb89bd636e763e1c5acb03776f97c011))
* **memory-quiz:** synchronize card display across all players in multiplayer ([472f201](https://github.com/antialias/soroban-abacus-flashcards/commit/472f201088d82f92030273fadaf8a8e488820d6c))
* **migrations:** add migration 0009 for display_password column ([040d749](https://github.com/antialias/soroban-abacus-flashcards/commit/040d7495a0801076b252d2574023f5323540db1a))
* **moderation:** don't show pending invitation for users already in room ([fae5920](https://github.com/antialias/soroban-abacus-flashcards/commit/fae5920e2fda910f8db724103a837537b1063ac7))
* **moderation:** improve access mode settings UX ([dd9e657](https://github.com/antialias/soroban-abacus-flashcards/commit/dd9e657db85752b32ff91ae1b33a0bf7a7628e07))
* move invitations into nav and filter out current/banned rooms ([cfaf82b](https://github.com/antialias/soroban-abacus-flashcards/commit/cfaf82b2cc93c6da1dcceb5aea8d0bd2c7b14cea))
* **nav:** add delay to hamburger menu hover to prevent premature closing ([95cd72e](https://github.com/antialias/soroban-abacus-flashcards/commit/95cd72e9bf410c7772999a17fae88719dd6e404e))
* **nav:** add z-index to turn labels to prevent avatar overlap ([7c294da](https://github.com/antialias/soroban-abacus-flashcards/commit/7c294dafff4e4d70831e12897aec06092cd3ff3f))
* **nav:** close hamburger menu when nested dropdown closes and mouse not hovering ([7d65212](https://github.com/antialias/soroban-abacus-flashcards/commit/7d652126d04239d1971b8aa302137295a3dde90b))
* **nav:** enable tooltips for local players during gameplay ([5499700](https://github.com/antialias/soroban-abacus-flashcards/commit/54997007b8485c4d7c605d5b6179cedef3fdc9c7))
* **nav:** improve readability of turn label text ([bbd1da0](https://github.com/antialias/soroban-abacus-flashcards/commit/bbd1da02b5e94d625844d9301c617da98d01868a))
* **nav:** improve text contrast in room info pane ([3e691cb](https://github.com/antialias/soroban-abacus-flashcards/commit/3e691cb06d64e32f65146ffd690fa1c25e9b487d))
* **nav:** navigate to /arcade/room (not /arcade/rooms/{id}) ([1c55f36](https://github.com/antialias/soroban-abacus-flashcards/commit/1c55f3630cb5f07b685555e41baa5a49314f15a3))
* **nav:** navigate to room after creation from (+) menu ([21e6e33](https://github.com/antialias/soroban-abacus-flashcards/commit/21e6e33173e7939102a7e6d6a7bd5168a97a49d6))
* **nav:** prevent hamburger menu from closing when toggling Style dropdown ([a898fbc](https://github.com/antialias/soroban-abacus-flashcards/commit/a898fbc187bf5286f63719420e0e98654ef25bb3))
* **nav:** prevent style dropdown from closing hamburger menu ([560a052](https://github.com/antialias/soroban-abacus-flashcards/commit/560a05266e15b51089cfd127b4ebe0990f04e64d))
* **nav:** prevent turn label text from being obscured ([c4b00dd](https://github.com/antialias/soroban-abacus-flashcards/commit/c4b00dd679aa2f87ae6b84a37e5b6d0d38113606))
* **nav:** properly prevent nested style dropdown from closing hamburger menu ([c5b6a82](https://github.com/antialias/soroban-abacus-flashcards/commit/c5b6a82ca42e0f9b381f2086e825e3ce36d738a9))
* **nav:** remove animation/enlargement from network player turn indicator ([53079ed](https://github.com/antialias/soroban-abacus-flashcards/commit/53079ede13ce9734cd3e702f27e6cb8f7fff626e))
* **nav:** remove blue gradient background from network players ([2881aff](https://github.com/antialias/soroban-abacus-flashcards/commit/2881affecca16afefdeb05aecdbb3648cba05691))
* **nav:** remove opacity reduction from local players ([5215af8](https://github.com/antialias/soroban-abacus-flashcards/commit/5215af801fc7e7412dc1c84e6abf1231f7670bfb))
* **nav:** remove play arrow badge from turn indicators ([80cfc10](https://github.com/antialias/soroban-abacus-flashcards/commit/80cfc10f7887533b20d663f320696917e1856899))
* **nav:** update types for registry games with nullable gameName ([a51e539](https://github.com/antialias/soroban-abacus-flashcards/commit/a51e539d023681daf639ec104e79079c8ceec98e))
* **number-guesser:** add turn indicators, error feedback, and fix player ordering ([9f62623](https://github.com/antialias/soroban-abacus-flashcards/commit/9f626236845493ef68e1b3626e80efa35637b449))
* pixel-perfect alignment across all nav elements ([fa78a2c](https://github.com/antialias/soroban-abacus-flashcards/commit/fa78a2c001f3530b0a0929411e6e0addbc0abda0))
* **player-config:** correct label positioning in player settings dialog ([554cc40](https://github.com/antialias/soroban-abacus-flashcards/commit/554cc4063bc756c9c9cd1adf0c1964d3f2f6151b))
* populate session activePlayers from room members on join ([2d00939](https://github.com/antialias/soroban-abacus-flashcards/commit/2d00939f1b59a10d271f82098c1b88acb2245ce1))
* prevent duplicate arcade sessions per room ([4cc3de5](https://github.com/antialias/soroban-abacus-flashcards/commit/4cc3de5f43711bb2ffe9b10052108b27bba6889c))
* remove duplicate ModerationNotifications causing double toasts ([c6886a0](https://github.com/antialias/soroban-abacus-flashcards/commit/c6886a0e59b3cbf051a828e0157495101cd8c823))
* replace isLocked with accessMode and add bcryptjs ([a74b96b](https://github.com/antialias/soroban-abacus-flashcards/commit/a74b96bb6fe331d27f3d27b8f77a3ce32b254bce))
* replace last remaining isLoading with isPending in CreateRoomModal ([85d13cc](https://github.com/antialias/soroban-abacus-flashcards/commit/85d13cc552cfe2e825f8ea20c7db00d666599134))
* replace native alerts with inline confirmations in ModerationPanel ([ebe123e](https://github.com/antialias/soroban-abacus-flashcards/commit/ebe123ed7edf24fbc7b8765ed709455a8513d6d5))
* reset join request toast state when moderation event cleared ([6beb58a](https://github.com/antialias/soroban-abacus-flashcards/commit/6beb58a7b8f8e1841c71729a3517ab459e924aa9))
* resolve Memory Quiz room-based multiplayer validation issues ([2ffeade](https://github.com/antialias/soroban-abacus-flashcards/commit/2ffeade43710b5f3fff9991cc84763bbdbf97010))
* resolve TypeScript errors in MemoryGrid and StandardGameLayout ([cabbc82](https://github.com/antialias/soroban-abacus-flashcards/commit/cabbc821955d70f118630dc21a9fcbb6d340f278))
* **room-data:** update query cache when gameConfig changes ([7cea297](https://github.com/antialias/soroban-abacus-flashcards/commit/7cea297095b78d74f5b77ca83489ec1be684a486))
* **rooms:** add real-time ownership transfer updates via WebSocket ([c00cfa3](https://github.com/antialias/soroban-abacus-flashcards/commit/c00cfa3de011720f3399fa340182b347f7e0d456))
* **room:** update GAME_TYPE_TO_NAME mapping for memory-quiz ([4afa171](https://github.com/antialias/soroban-abacus-flashcards/commit/4afa171af212902120599b3d68f58cfbdf7820b0))
* set color on abacus container div for numeral visibility ([cd47960](https://github.com/antialias/soroban-abacus-flashcards/commit/cd4796024e41f731ae5d83c82f6582e19d6eaf99)), closes [#1f2937](https://github.com/antialias/soroban-abacus-flashcards/issues/1f2937)
* show initial value and improve numeral contrast ([1b57f6d](https://github.com/antialias/soroban-abacus-flashcards/commit/1b57f6ddecf3a118f2e4fadd1a91be1256f5a034)), closes [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24)
* simplify abacus pane with light background ([30f48ab](https://github.com/antialias/soroban-abacus-flashcards/commit/30f48ab8976976688e089b07ece7fdae6d7ada79))
* **socket-io:** update import path for socket-server module ([1a64dec](https://github.com/antialias/soroban-abacus-flashcards/commit/1a64decf5afe67c16e1aec283262ffa6132dcd83))
* stack game title dropdown ABOVE room pane, not inside it ([7bc815f](https://github.com/antialias/soroban-abacus-flashcards/commit/7bc815fd7dbbb1489a17782b2df0c3fe508dd574))
* **toast:** scope animations to prevent affecting other UI elements ([245ed8a](https://github.com/antialias/soroban-abacus-flashcards/commit/245ed8a625ba848f8cd79d51bfd88600cd77f0b9))
* **tutorial:** correct column index calculation for variable column counts ([bf1ced4](https://github.com/antialias/soroban-abacus-flashcards/commit/bf1ced43f801938b05f01548eea5fe771de1b58f))
* **tutorial:** filter bead highlights when using fewer columns ([4d906ec](https://github.com/antialias/soroban-abacus-flashcards/commit/4d906ec20e90a9b0b3838f9b8428e0c68992f381))
* **tutorial:** reduce tooltip z-index to scroll under nav bar ([47640f3](https://github.com/antialias/soroban-abacus-flashcards/commit/47640f3486c6d4a7107d59bdcce043f76fabbb1d))
* **tutorial:** resolve React hydration error in TutorialPlayer ([c883d9e](https://github.com/antialias/soroban-abacus-flashcards/commit/c883d9e4c1b3a2f52c9d41e3ddce7418399f2649))
* **tutorial:** resolve TypeScript errors in TutorialPlayer ([88f57ce](https://github.com/antialias/soroban-abacus-flashcards/commit/88f57ce6df125142d6ea7feec60c475926bd4929))
* **tutorial:** use correct customStyles API for dark mode frame styling ([fdc882c](https://github.com/antialias/soroban-abacus-flashcards/commit/fdc882cb046e3d8835fbca59841e9af5329bcc52))
* update locked room terminology and allow existing members ([1ddf985](https://github.com/antialias/soroban-abacus-flashcards/commit/1ddf985938d9542fe26e44da58234f3d4e3c9543))
* use app-wide abacus config and remove instruction text ([0a50c73](https://github.com/antialias/soroban-abacus-flashcards/commit/0a50c733b089c7c341f0fdef47da78d1c61a3cb5))
* use color instead of fill for numeral styling ([ea10c16](https://github.com/antialias/soroban-abacus-flashcards/commit/ea10c16811eb969b9963417079c330ae9ff295ba))
* use defaultValue for interactive abacus control ([06aca98](https://github.com/antialias/soroban-abacus-flashcards/commit/06aca986ace4d76b70f2fd2f5e57f66758185b38))
* use useCreateRoom hook instead of nonexistent createRoom from useRoomData ([f7d63b3](https://github.com/antialias/soroban-abacus-flashcards/commit/f7d63b30ac498b63797ae8683a0beb435a1c97b3))
### Code Refactoring
* **db:** remove database schema coupling for game names ([e135d92](https://github.com/antialias/soroban-abacus-flashcards/commit/e135d92abb4d27f646c1fbeff6524a729d107426)), closes [#1](https://github.com/antialias/soroban-abacus-flashcards/issues/1)
### Features
* **abacus-react:** add BigInt support for 30-digit Dan level abacuses ([0ab4cc2](https://github.com/antialias/soroban-abacus-flashcards/commit/0ab4cc288066b75a6ea4371f65098db5c0fc8847))
* add API routes for moderation and invitations ([79a8518](https://github.com/antialias/soroban-abacus-flashcards/commit/79a85185575571cf628d655b0558f8246d2b02c7))
* add backend library functions for room moderation ([84f3c4b](https://github.com/antialias/soroban-abacus-flashcards/commit/84f3c4bcfd258cb2e54b89b55d5162af57b74fe5))
* add common UI components ([cd3115a](https://github.com/antialias/soroban-abacus-flashcards/commit/cd3115aa6d6bb8cf227b3d15d055f27dc5377a00))
* add database schema for room moderation and invitations ([97d1604](https://github.com/antialias/soroban-abacus-flashcards/commit/97d16041dfe33bd817df2472323962dc4e94f8ee))
* add drizzle migration for room_game_configs table ([3bae00b](https://github.com/antialias/soroban-abacus-flashcards/commit/3bae00b9a9dc925039a02fe07d036a2fc5e0fb79))
* add fun automatic player naming system ([249257c](https://github.com/antialias/soroban-abacus-flashcards/commit/249257c6c77d503b48479065664c96c5de36a234))
* add invitation system UI components ([fd3a2d1](https://github.com/antialias/soroban-abacus-flashcards/commit/fd3a2d1f76eb12473bb2b5a33453362d6889d7b0))
* add moderation panel with unban & invite feature ([a2d0169](https://github.com/antialias/soroban-abacus-flashcards/commit/a2d0169f8063f00726ce2769bd5db270cfa82f4d))
* add name generator button and abacus emoji ([07212e4](https://github.com/antialias/soroban-abacus-flashcards/commit/07212e4df0c7fd4b8cccf935c48b14164df6961d))
* add player count to stacked room info ([540f6b7](https://github.com/antialias/soroban-abacus-flashcards/commit/540f6b76d05f561baa581d67070ab43134d8b5f6))
* add prominent join request approval notifications for room moderators ([036da6d](https://github.com/antialias/soroban-abacus-flashcards/commit/036da6de66ca7d3f459c55df657b04a9e88d9cd3))
* add real-time socket updates for moderation events ([86ceba3](https://github.com/antialias/soroban-abacus-flashcards/commit/86ceba3df3d39812d63fbf5d03fc37d8c3a75027))
* add room access modes and ownership transfer ([6ff21c4](https://github.com/antialias/soroban-abacus-flashcards/commit/6ff21c4f1dd0dd1db14257612809b4d40512689a))
* add room creation and join flow UI ([7f95032](https://github.com/antialias/soroban-abacus-flashcards/commit/7f950322530e8deb2e330d0d2147d1a20fa1e642))
* add socket listener and polling for approval notifications ([35b4a72](https://github.com/antialias/soroban-abacus-flashcards/commit/35b4a72c8b2f80a74b5d2fe02b048d4ec4d1d6f2))
* add waiting state for approval requests in JoinRoomModal ([f9b0429](https://github.com/antialias/soroban-abacus-flashcards/commit/f9b0429a2e2d22944acba66009dd87a9d9eb28c2))
* adjust tier probabilities for more abacus flavor ([49219e3](https://github.com/antialias/soroban-abacus-flashcards/commit/49219e34cde32736155a11929d10581e783cba69))
* **arcade:** add Card Sorting Challenge game scaffolding ([df37260](https://github.com/antialias/soroban-abacus-flashcards/commit/df37260e26bbb146493e0834e093afd98fa3f2a4))
* **arcade:** add Change Game functionality for room hosts ([ee39241](https://github.com/antialias/soroban-abacus-flashcards/commit/ee39241e3c9e04202592497d9987eafcb89c00c9))
* **arcade:** add game selection screen with navigation to room page ([4124f1c](https://github.com/antialias/soroban-abacus-flashcards/commit/4124f1cc081f5cb9d6f450f3c2e0cca8a247deba))
* **arcade:** add Math Sprint game implementation ([e5be09e](https://github.com/antialias/soroban-abacus-flashcards/commit/e5be09ef5f170c7544557f75b9eca17bb2069246))
* **arcade:** add modular game SDK and registry system ([de30bec](https://github.com/antialias/soroban-abacus-flashcards/commit/de30bec47923565fe5d1d5a6f719f3fc4e9d1509))
* **arcade:** add Number Guesser demo game with plugin architecture ([0e3c058](https://github.com/antialias/soroban-abacus-flashcards/commit/0e3c0587073a69574a50f05c467f2499296012bf))
* **arcade:** broadcast game selection changes to all room members ([b99e754](https://github.com/antialias/soroban-abacus-flashcards/commit/b99e7543952bb0d47f42e79dc4226b3c1280a0ee))
* **arcade:** migrate matching pairs - phases 1-4 and 7 complete ([2a3af97](https://github.com/antialias/soroban-abacus-flashcards/commit/2a3af973f70ff07de30b38bbe1cdc549a971846f))
* **arcade:** migrate memory-quiz to modular game system ([f48c37a](https://github.com/antialias/soroban-abacus-flashcards/commit/f48c37accccb88e790c7a1b438fd0566e7120e11))
* **arcade:** register Math Sprint in game system ([0c05a7c](https://github.com/antialias/soroban-abacus-flashcards/commit/0c05a7c6bbc8d6f6e1f92e15e691d7e1aba0d8f7)), closes [#2](https://github.com/antialias/soroban-abacus-flashcards/issues/2) [#3](https://github.com/antialias/soroban-abacus-flashcards/issues/3)
* **card-sorting:** add spectator mode UX enhancements ([4ab093a](https://github.com/antialias/soroban-abacus-flashcards/commit/4ab093a9d8ba5b290da44aaa6aa71ad7d7149b32))
* **card-sorting:** add UI components and fix AbacusReact props ([d249ec0](https://github.com/antialias/soroban-abacus-flashcards/commit/d249ec0e5ff4610f55f35f762d726e0c98ac366c))
* **card-sorting:** implement Provider with arcade session integration ([7f6fea9](https://github.com/antialias/soroban-abacus-flashcards/commit/7f6fea91f6dcc69a173eea86bcefc9921f1c1664))
* **complement-race:** add infinite win condition for Steam Sprint mode ([d8fdfee](https://github.com/antialias/soroban-abacus-flashcards/commit/d8fdfeef74a5d3bb9684254af1c9d64d264b46ad))
* **complement-race:** add mini app navigation bar ([ed0ef2d](https://github.com/antialias/soroban-abacus-flashcards/commit/ed0ef2d3b87324470d06b3246652967544caec26))
* **complement-race:** enable adaptive AI difficulty in arcade ([55010d2](https://github.com/antialias/soroban-abacus-flashcards/commit/55010d2bcd953718d8fea428b1f7f613a193779c))
* **complement-race:** implement state adapter for multiplayer support ([13882bd](https://github.com/antialias/soroban-abacus-flashcards/commit/13882bda3258d68a817473d7d830381f02553043))
* **complement-race:** restore AI opponents in practice and survival modes ([325e07d](https://github.com/antialias/soroban-abacus-flashcards/commit/325e07de5929169aa333ef16f7bca5b41eeb1622))
* **homepage:** add animated mini abacus to "Read and set numbers" card ([e028e34](https://github.com/antialias/soroban-abacus-flashcards/commit/e028e342ad4bc01491e05a4ba074628155926fd8))
* **homepage:** add more visual embellishments to learning cards ([4ec1b95](https://github.com/antialias/soroban-abacus-flashcards/commit/4ec1b952f202d50f6db287c41732ec65ca17c142))
* **homepage:** enhance "What You'll Learn" with visual cards ([d142342](https://github.com/antialias/soroban-abacus-flashcards/commit/d1423420e653b26b2f89d9d17ae5d597807d6979))
* **home:** redesign home page to showcase complete platform ([ee6c4f2](https://github.com/antialias/soroban-abacus-flashcards/commit/ee6c4f2f4f39e3b30f59c54866c3857c218fb80f))
* implement approval request flow for share links ([4a6b3ca](https://github.com/antialias/soroban-abacus-flashcards/commit/4a6b3cabe5c6aa42f4fa00ed09f9b3713f097539))
* implement avatar-themed name generation with probabilistic mixing ([76a8472](https://github.com/antialias/soroban-abacus-flashcards/commit/76a8472f12d251071b97f2288f62f0b358576232))
* implement proper retired room behavior with member expulsion ([a2d5368](https://github.com/antialias/soroban-abacus-flashcards/commit/a2d53680f27db04b2cd09973e62a76c5a7d4ce06))
* improve arcade nav player grouping and add room join code display ([8e9980d](https://github.com/antialias/soroban-abacus-flashcards/commit/8e9980dc82ba2ab4ce973fc2c7ed259a20af9b19))
* improve room creation UX and add password support for share links ([dcbb507](https://github.com/antialias/soroban-abacus-flashcards/commit/dcbb5072d8e0a12838fe70e3faa85f94cd63b0c1))
* integrate moderation system into arcade pages ([087652f](https://github.com/antialias/soroban-abacus-flashcards/commit/087652f9e7091a93c02906162275ef88ec5e44c6))
* **levels:** add Dan levels ladder visualization ([c18012c](https://github.com/antialias/soroban-abacus-flashcards/commit/c18012cb505a1f2a86ebed7579b379a4d7d97f2c))
* **levels:** add dark mode styling and responsive scaling to abacus ([92e1e62](https://github.com/antialias/soroban-abacus-flashcards/commit/92e1e621321039206f65b3605f5797bbdc6beafc))
* **levels:** add informational footer section ([0b1bff7](https://github.com/antialias/soroban-abacus-flashcards/commit/0b1bff7eab8f5da84ae309dbda336e168c2fe3fd))
* **levels:** add Kyu & Dan levels page with homepage link ([39b1e7d](https://github.com/antialias/soroban-abacus-flashcards/commit/39b1e7de16f15412c91cf648c714e31e2de7a6bc))
* **levels:** add kyu level data and cards ([6463a3b](https://github.com/antialias/soroban-abacus-flashcards/commit/6463a3b2f6371ebebac1048197fb44178997d2ef))
* **levels:** create true horizontal slider with abacus visualizations ([6d734f1](https://github.com/antialias/soroban-abacus-flashcards/commit/6d734f1d51f5ba1367f55923e58bd977413d754e))
* **levels:** implement interactive slider for exploring kyu & dan ranks ([eb3b100](https://github.com/antialias/soroban-abacus-flashcards/commit/eb3b1000563536d4143ba1f4ec04e59e8dd2e608))
* **levels:** replace kyu grid with interactive slider and abacus visualizations ([10978e8](https://github.com/antialias/soroban-abacus-flashcards/commit/10978e890beee65dea78ddcce52cfe5315d58063))
* make home page abacus interactive with audio ([9a53d7e](https://github.com/antialias/soroban-abacus-flashcards/commit/9a53d7e5db18853aca4e2e0c7abc799217feaecf))
* **matching:** use nav avatars as turn indicators ([7263828](https://github.com/antialias/soroban-abacus-flashcards/commit/7263828ed494a6487999c8436af53618715b3864))
* **math-sprint:** add game manifest ([1eefcc8](https://github.com/antialias/soroban-abacus-flashcards/commit/1eefcc89a58b79f928932a7425d6b88fb45a5526))
* **memory-quiz:** add multiplayer support with redesigned scoreboards ([1cf4469](https://github.com/antialias/soroban-abacus-flashcards/commit/1cf44696c26473ce4ab2fc2039ff42f08c20edb6))
* **memory-quiz:** persist game settings per-game across sessions ([05a8e0a](https://github.com/antialias/soroban-abacus-flashcards/commit/05a8e0a84272c6c45a4014413ee00726eb88b76a))
* **memory-quiz:** show player emojis on cards to indicate who found them ([05bd11a](https://github.com/antialias/soroban-abacus-flashcards/commit/05bd11a133706c9ed8c09c744da7ca8955fa979a))
* **moderation:** add inline feedback and persistent password display ([86e3d41](https://github.com/antialias/soroban-abacus-flashcards/commit/86e3d4199628f95048b9265c9de0adfdc2934f93))
* **moderation:** improve password input with copy button ([2580e47](https://github.com/antialias/soroban-abacus-flashcards/commit/2580e474d08bf91477339e998b2c70962a633f41))
* **nav:** add prominent turn indicator arrow badge ([f574558](https://github.com/antialias/soroban-abacus-flashcards/commit/f574558dffe22a1ecf06ee44d37b5eb1a20011b9))
* **nav:** add pulsing indicator for offline network players ([64fb30e](https://github.com/antialias/soroban-abacus-flashcards/commit/64fb30e7eca7b485687329b9dd3d9e90ac507e2d))
* **nav:** add turn indicators to network players ([623314b](https://github.com/antialias/soroban-abacus-flashcards/commit/623314bd383a54c57ca93ad9f2d8620cf89412e9))
* **nav:** add turn label text under current player avatars ([52a66d5](https://github.com/antialias/soroban-abacus-flashcards/commit/52a66d5f6869e760f2a8914a6d39d21d47cfb7f4))
* **nav:** center game context with hamburger menu for utilities ([a35a7d5](https://github.com/antialias/soroban-abacus-flashcards/commit/a35a7d56df945a5b15c1ddfa8b489c0d292e71c4))
* **nav:** combine room info and network players in single pane ([d5473ab](https://github.com/antialias/soroban-abacus-flashcards/commit/d5473ab66a7c8c78f10cef9bb7084fc311520b2c))
* **nav:** unify room dropdown with join code and game menu ([f7b83f8](https://github.com/antialias/soroban-abacus-flashcards/commit/f7b83f8c149b532321251abed98a94874196b2f5))
* prevent invitations to retired rooms ([a7c3c1f](https://github.com/antialias/soroban-abacus-flashcards/commit/a7c3c1f4cd802985c8f040bc1cdf3ea4482a2fce))
* redesign home page with component showcase ([29af265](https://github.com/antialias/soroban-abacus-flashcards/commit/29af265958f9fdab0253b92e153c01575840454d))
* redesign homepage with educational vision and interactive demo ([2f09cb5](https://github.com/antialias/soroban-abacus-flashcards/commit/2f09cb5539f2bb0b8c77359c6f774c3742313e1e))
* redesign room info as compact inline badge with click-to-copy ([6b3a440](https://github.com/antialias/soroban-abacus-flashcards/commit/6b3a4403695cc2f32df684005784a11f054827ff))
* replace access mode dropdown with visual button grid ([e5d0672](https://github.com/antialias/soroban-abacus-flashcards/commit/e5d067205989d7c3105998dcd7d67fd0408f332c))
* **tutorial:** add dark mode styling for coaching bar and abacus frame ([7e2f580](https://github.com/antialias/soroban-abacus-flashcards/commit/7e2f580877af9d21409f427778fa3569c950fcf5))
* **tutorial:** add dark theme and column control props ([d42f9b2](https://github.com/antialias/soroban-abacus-flashcards/commit/d42f9b2d9ad630826c55b753dc581c469e8f9083))
* **tutorial:** add fill color support for dark mode column posts and reckoning bar ([2eb3ff3](https://github.com/antialias/soroban-abacus-flashcards/commit/2eb3ff340613301df20bf14f5b461371a27d7f05))
* **tutorial:** add hideNavigation prop to TutorialPlayer ([79ea52a](https://github.com/antialias/soroban-abacus-flashcards/commit/79ea52af80c8cbb482bbdd87f77caf32ada737ee))
* **tutorial:** add hideTooltip prop and improve dark mode coaching bar ([1ee25b3](https://github.com/antialias/soroban-abacus-flashcards/commit/1ee25b3dd2f0ee9dd7ed571ba818b7ca5a247f85))
* **tutorial:** add silentErrors prop to suppress error messages ([8835e1c](https://github.com/antialias/soroban-abacus-flashcards/commit/8835e1c57ab8adcecefe0db082360dd98fbfaac7))
### Reverts
* **nav:** restore original room creation/join behavior ([710e93c](https://github.com/antialias/soroban-abacus-flashcards/commit/710e93c9972339885b8f4ca02ecd2c1cdf65c040))
### BREAKING CHANGES
* **db:** Database schemas now accept any string for game names
* Added DELETE /api/arcade/rooms/:roomId/invite endpoint for declining invitations
Authorization Error Handling:
- ModerationPanel: Parse and display API error messages (kick, ban, unban, invite, data loading)
- PendingInvitations: Parse and display API error messages (decline, fetch)
- All moderation actions now show specific auth errors like "Only the host can kick users"
New Endpoint:
- DELETE /api/arcade/rooms/:roomId/invite: Allow users to decline their pending invitations
* Validates invitation exists and is pending
* Only invited user can decline their own invitation
* Returns proper error messages for auth failures
Bug Fix:
- Fixed invitations/pending/route.ts ban check query (removed reference to non-existent unbannedAt field)
- Ban records are deleted when unbanned, so any existing ban is active
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
# [1.8.0](https://github.com/antialias/soroban-abacus-flashcards/compare/abacus-react-v1.7.0...abacus-react-v1.8.0) (2025-10-10)

View File

@@ -213,7 +213,7 @@ export interface AbacusCallbacks {
value: number,
event: React.MouseEvent,
) => void;
onValueChange?: (newValue: number) => void;
onValueChange?: (newValue: number | bigint) => void;
onBeadRef?: (bead: BeadConfig, element: SVGElement | null) => void;
// Legacy callback for backward compatibility
onClick?: (bead: BeadConfig) => void;
@@ -240,7 +240,7 @@ export interface AbacusOverlay {
export interface AbacusConfig {
// Basic configuration
value?: number;
value?: number | bigint;
columns?: number | "auto";
showEmptyColumns?: boolean;
hideInactiveBeads?: boolean;
@@ -271,7 +271,7 @@ export interface AbacusConfig {
// Legacy callbacks for backward compatibility
onClick?: (bead: BeadConfig) => void;
onValueChange?: (newValue: number) => void;
onValueChange?: (newValue: number | bigint) => void;
}
export interface AbacusDimensions {
@@ -474,18 +474,23 @@ export function useAbacusState(
// NEW: Native place-value state management hook (eliminates the column index nightmare!)
export function useAbacusPlaceStates(
controlledValue: number = 0,
controlledValue: number | bigint = 0,
maxPlaceValue: ValidPlaceValues = 4,
) {
// Initialize state from value using place values as keys - NO MORE ARRAY INDICES!
const initializeFromValue = useCallback(
(value: number): PlaceStatesMap => {
(value: number | bigint): PlaceStatesMap => {
const states = new Map<ValidPlaceValues, PlaceState>();
// Convert to string to handle both number and bigint
const valueStr = value.toString();
const digits = valueStr.split('').map(Number);
// Always create ALL place values from 0 to maxPlaceValue (to match columns)
for (let place = 0; place <= maxPlaceValue; place++) {
const placeValueNum = Math.pow(10, place);
const digit = Math.floor(value / placeValueNum) % 10;
// Get digit from right: place 0 = rightmost, place 1 = second from right, etc.
const digitIndex = digits.length - 1 - place;
const digit = digitIndex >= 0 ? digits[digitIndex] : 0;
states.set(place as ValidPlaceValues, {
placeValue: place as ValidPlaceValues,
@@ -504,18 +509,32 @@ export function useAbacusPlaceStates(
);
// Calculate current value from place states - NO MORE INDEX MATH!
// Use BigInt for numbers that exceed safe integer range (>15 digits)
const value = useMemo(() => {
let total = 0;
placeStates.forEach((state) => {
const placeValueNum = Math.pow(10, state.placeValue);
const digitValue = (state.heavenActive ? 5 : 0) + state.earthActive;
total += digitValue * placeValueNum;
});
return total;
}, [placeStates]);
// Check if we need BigInt (maxPlaceValue > 14 means >15 digits)
const useBigInt = maxPlaceValue > 14;
if (useBigInt) {
let total = 0n;
placeStates.forEach((state) => {
const placeValueNum = 10n ** BigInt(state.placeValue);
const digitValue = BigInt((state.heavenActive ? 5 : 0) + state.earthActive);
total += digitValue * placeValueNum;
});
return total;
} else {
let total = 0;
placeStates.forEach((state) => {
const placeValueNum = Math.pow(10, state.placeValue);
const digitValue = (state.heavenActive ? 5 : 0) + state.earthActive;
total += digitValue * placeValueNum;
});
return total;
}
}, [placeStates, maxPlaceValue]);
const setValue = useCallback(
(newValue: number) => {
(newValue: number | bigint) => {
setPlaceStates(initializeFromValue(newValue));
},
[initializeFromValue],
@@ -531,6 +550,37 @@ export function useAbacusPlaceStates(
}
}, [controlledValue, initializeFromValue, value]);
// Clean up place states when maxPlaceValue decreases (columns decrease)
// This prevents stale place values from causing out-of-bounds access
React.useEffect(() => {
setPlaceStates((prev) => {
const newStates = new Map(prev);
let hasChanges = false;
// Remove any place values greater than maxPlaceValue
for (const placeValue of newStates.keys()) {
if (placeValue > maxPlaceValue) {
newStates.delete(placeValue);
hasChanges = true;
}
}
// Add missing place values up to maxPlaceValue
for (let place = 0; place <= maxPlaceValue; place++) {
if (!newStates.has(place as ValidPlaceValues)) {
newStates.set(place as ValidPlaceValues, {
placeValue: place as ValidPlaceValues,
heavenActive: false,
earthActive: 0,
});
hasChanges = true;
}
}
return hasChanges ? newStates : prev;
});
}, [maxPlaceValue]);
const getPlaceState = useCallback(
(placeValue: ValidPlaceValues): PlaceState => {
return (
@@ -1058,13 +1108,15 @@ function calculateBeadStates(
// NEW: Native place-value bead state calculation (eliminates array index math!)
function calculateBeadStatesFromPlaces(
placeStates: PlaceStatesMap,
maxPlaceValue: ValidPlaceValues,
): BeadConfig[][] {
const columnsList: BeadConfig[][] = [];
// Convert Map to sorted array by place value (ascending order for correct visual layout)
const sortedPlaces = Array.from(placeStates.entries()).sort(
([a], [b]) => a - b,
);
// Filter to only include place values that are within the current column count
const sortedPlaces = Array.from(placeStates.entries())
.filter(([placeValue]) => placeValue <= maxPlaceValue)
.sort(([a], [b]) => a - b);
for (const [placeValue, placeState] of sortedPlaces) {
const beads: BeadConfig[] = [];
@@ -1114,17 +1166,26 @@ function calculateValueFromColumnStates(
}
// NEW: Native place-value calculation (eliminates the array index nightmare!)
function calculateValueFromPlaceStates(placeStates: PlaceStatesMap): number {
let value = 0;
function calculateValueFromPlaceStates(placeStates: PlaceStatesMap): number | bigint {
// Determine if we need BigInt based on the largest place value
const maxPlace = Math.max(...Array.from(placeStates.keys()));
const useBigInt = maxPlace > 14; // >15 digits
// Direct place value iteration - NO MORE ARRAY INDEX MATH!
for (const [placeValue, placeState] of placeStates) {
const digitValue =
(placeState.heavenActive ? 5 : 0) + placeState.earthActive;
value += digitValue * Math.pow(10, placeValue); // Direct place value - no conversion!
if (useBigInt) {
let value = 0n;
for (const [placeValue, placeState] of placeStates) {
const digitValue = BigInt((placeState.heavenActive ? 5 : 0) + placeState.earthActive);
value += digitValue * (10n ** BigInt(placeValue));
}
return value;
} else {
let value = 0;
for (const [placeValue, placeState] of placeStates) {
const digitValue = (placeState.heavenActive ? 5 : 0) + placeState.earthActive;
value += digitValue * Math.pow(10, placeValue);
}
return value;
}
return value;
}
// Components
@@ -1588,8 +1649,8 @@ export const AbacusReact: React.FC<AbacusConfig> = ({
// Use new place-value bead calculation!
const beadStates = useMemo(
() => calculateBeadStatesFromPlaces(placeStates),
[placeStates],
() => calculateBeadStatesFromPlaces(placeStates, maxPlaceValue),
[placeStates, maxPlaceValue],
);
// Layout calculations using exact Typst positioning
@@ -1939,6 +2000,7 @@ export const AbacusReact: React.FC<AbacusConfig> = ({
{/* Background glow effects - rendered behind everything */}
{Array.from({ length: effectiveColumns }, (_, colIndex) => {
const placeValue = effectiveColumns - 1 - colIndex;
const columnStyles = customStyles?.columns?.[colIndex];
const backgroundGlow = columnStyles?.backgroundGlow;
@@ -1952,7 +2014,7 @@ export const AbacusReact: React.FC<AbacusConfig> = ({
return (
<rect
key={`background-glow-${colIndex}`}
key={`background-glow-pv${placeValue}`}
x={x - glowWidth / 2}
y={-(backgroundGlow.spread || 0) / 2}
width={glowWidth}
@@ -1970,6 +2032,7 @@ export const AbacusReact: React.FC<AbacusConfig> = ({
{/* Rods - positioned as rectangles like in Typst */}
{Array.from({ length: effectiveColumns }, (_, colIndex) => {
const placeValue = effectiveColumns - 1 - colIndex;
const x =
colIndex * dimensions.rodSpacing + dimensions.rodSpacing / 2;
@@ -2001,7 +2064,7 @@ export const AbacusReact: React.FC<AbacusConfig> = ({
return (
<rect
key={`rod-${colIndex}`}
key={`rod-pv${placeValue}`}
x={x - dimensions.rodWidth / 2}
y={rodStartY}
width={dimensions.rodWidth}
@@ -2056,6 +2119,15 @@ export const AbacusReact: React.FC<AbacusConfig> = ({
} else {
// Earth bead positioning - exact Typst formulas (lines 249-261)
const columnState = columnStates[colIndex];
if (!columnState) {
throw new Error(
`Invalid abacus state: columnState is undefined for column index ${colIndex}. ` +
`effectiveColumns=${effectiveColumns}, columnStates.length=${columnStates.length}, ` +
`beadStates.length=${beadStates.length}, placeValue=${bead.placeValue}. ` +
`This indicates a mismatch between the number of columns and the bead states. ` +
`Please report this issue with the abacus configuration that triggered it.`
);
}
const earthActive = columnState.earthActive;
if (bead.active) {
@@ -2134,7 +2206,7 @@ export const AbacusReact: React.FC<AbacusConfig> = ({
return (
<Bead
key={`bead-${colIndex}-${bead.type}-${beadIndex}`}
key={`bead-pv${bead.placeValue}-${bead.type}-${bead.type === "earth" ? bead.position : 0}`}
bead={bead}
x={x}
y={y}
@@ -2208,6 +2280,7 @@ export const AbacusReact: React.FC<AbacusConfig> = ({
{/* Background rectangles for place values - in SVG */}
{finalConfig.showNumbers &&
placeValues.map((value, columnIndex) => {
const placeValue = effectiveColumns - 1 - columnIndex;
const x =
columnIndex * dimensions.rodSpacing + dimensions.rodSpacing / 2;
// Position background rectangles to match the text positioning
@@ -2220,7 +2293,7 @@ export const AbacusReact: React.FC<AbacusConfig> = ({
return (
<rect
key={`place-bg-${columnIndex}`}
key={`place-bg-pv${placeValue}`}
x={x - 12 * finalConfig.scaleFactor}
y={y - 12 * finalConfig.scaleFactor}
width={24 * finalConfig.scaleFactor}
@@ -2248,6 +2321,7 @@ export const AbacusReact: React.FC<AbacusConfig> = ({
{/* NumberFlow place value displays - inside SVG using foreignObject */}
{finalConfig.showNumbers &&
placeValues.map((value, columnIndex) => {
const placeValue = effectiveColumns - 1 - columnIndex;
const x =
columnIndex * dimensions.rodSpacing + dimensions.rodSpacing / 2;
// Position numbers within the allocated numbers space (below the baseHeight)
@@ -2259,7 +2333,7 @@ export const AbacusReact: React.FC<AbacusConfig> = ({
return (
<foreignObject
key={`place-number-${columnIndex}`}
key={`place-number-pv${placeValue}`}
x={x - 12 * finalConfig.scaleFactor}
y={y - 8 * finalConfig.scaleFactor}
width={24 * finalConfig.scaleFactor}
@@ -2320,6 +2394,12 @@ export const AbacusReact: React.FC<AbacusConfig> = ({
if (targetBeadType === "heaven") {
const columnState = columnStates[targetColumn];
if (!columnState) {
console.error(
`Invalid abacus overlay: columnState is undefined for overlay targeting column ${targetColumn}`
);
return;
}
y = columnState.heavenActive
? dimensions.heavenEarthGap -
dimensions.beadSize / 2 -
@@ -2332,6 +2412,12 @@ export const AbacusReact: React.FC<AbacusConfig> = ({
targetBeadPosition !== undefined
) {
const columnState = columnStates[targetColumn];
if (!columnState) {
console.error(
`Invalid abacus overlay: columnState is undefined for overlay targeting column ${targetColumn}`
);
return;
}
const earthActive = columnState.earthActive;
const isActive = targetBeadPosition < earthActive;
@@ -2403,6 +2489,7 @@ export const AbacusReact: React.FC<AbacusConfig> = ({
{/* Column interaction areas - rendered last to be on top of all other elements */}
{Array.from({ length: effectiveColumns }, (_, colIndex) => {
const placeValue = effectiveColumns - 1 - colIndex;
const x =
colIndex * dimensions.rodSpacing + dimensions.rodSpacing / 2;
const columnStyles = customStyles?.columns?.[colIndex];
@@ -2413,7 +2500,7 @@ export const AbacusReact: React.FC<AbacusConfig> = ({
return (
<rect
key={`column-interaction-${colIndex}`}
key={`column-interaction-pv${placeValue}`}
x={x - backgroundWidth / 2}
y={0}
width={backgroundWidth}

View File

@@ -0,0 +1,147 @@
"use client";
import React from "react";
import { useSpring, animated } from "@react-spring/web";
import {
useAbacusConfig,
getDefaultAbacusConfig,
type BeadShape,
} from "./AbacusContext";
export interface StandaloneBeadProps {
/** Size of the bead in pixels */
size?: number;
/** Override the shape from context (diamond, circle, square) */
shape?: BeadShape;
/** Override the color from context */
color?: string;
/** Enable animation */
animated?: boolean;
/** Custom className */
className?: string;
/** Custom style */
style?: React.CSSProperties;
/** Active state for the bead */
active?: boolean;
}
/**
* Standalone Bead component that respects the AbacusDisplayContext.
* This component renders a single abacus bead with styling from the context.
*
* Usage:
* ```tsx
* import { StandaloneBead, AbacusDisplayProvider } from '@soroban/abacus-react';
*
* <AbacusDisplayProvider>
* <StandaloneBead size={28} color="#8b5cf6" />
* </AbacusDisplayProvider>
* ```
*/
export const StandaloneBead: React.FC<StandaloneBeadProps> = ({
size = 28,
shape: shapeProp,
color: colorProp,
animated: animatedProp,
className,
style,
active = true,
}) => {
// Try to use context config, fallback to defaults if no context
let contextConfig;
try {
contextConfig = useAbacusConfig();
} catch {
// No context provider, use defaults
contextConfig = getDefaultAbacusConfig();
}
// Use props if provided, otherwise fall back to context config
const shape = shapeProp ?? contextConfig.beadShape;
const enableAnimation = animatedProp ?? contextConfig.animated;
const color = colorProp ?? "#000000";
const [springs, api] = useSpring(() => ({
scale: 1,
config: { tension: 300, friction: 20 },
}));
React.useEffect(() => {
if (enableAnimation) {
api.start({ scale: 1 });
}
}, [enableAnimation, api]);
const renderShape = () => {
const halfSize = size / 2;
const actualColor = active ? color : "rgb(211, 211, 211)";
switch (shape) {
case "diamond":
return (
<polygon
points={`${size * 0.7},0 ${size * 1.4},${halfSize} ${size * 0.7},${size} 0,${halfSize}`}
fill={actualColor}
stroke="#000"
strokeWidth="0.5"
/>
);
case "square":
return (
<rect
width={size}
height={size}
fill={actualColor}
stroke="#000"
strokeWidth="0.5"
rx="1"
/>
);
case "circle":
default:
return (
<circle
cx={halfSize}
cy={halfSize}
r={halfSize}
fill={actualColor}
stroke="#000"
strokeWidth="0.5"
/>
);
}
};
const getXOffset = () => {
return shape === "diamond" ? size * 0.7 : size / 2;
};
const getYOffset = () => {
return size / 2;
};
const AnimatedG = animated.g;
return (
<svg
width={size * (shape === "diamond" ? 1.4 : 1)}
height={size}
className={className}
style={style}
>
<AnimatedG
transform={`translate(0, 0)`}
style={
enableAnimation
? {
transform: springs.scale.to((s) => `scale(${s})`),
transformOrigin: "center",
}
: undefined
}
>
{renderShape()}
</AnimatedG>
</svg>
);
};

View File

@@ -14,3 +14,6 @@ export type {
AbacusDisplayConfig,
AbacusDisplayContextType,
} from "./AbacusContext";
export { StandaloneBead } from "./StandaloneBead";
export type { StandaloneBeadProps } from "./StandaloneBead";