Compare commits

...

6 Commits

Author SHA1 Message Date
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
4 changed files with 258 additions and 24 deletions

View File

@@ -1,3 +1,24 @@
## [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)

View File

@@ -7,6 +7,7 @@ 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 = [
@@ -181,6 +182,16 @@ const allLevels = [
},
] 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
}
export default function LevelsPage() {
const [currentIndex, setCurrentIndex] = useState(0)
const [isHovering, setIsHovering] = useState(false)
@@ -202,17 +213,18 @@ export default function LevelsPage() {
useEffect(() => {
// Calculate animation speed based on level
// Kyu levels: 500ms
// Dan levels: interpolate from 500ms (Pre-1st Dan) to 50ms (10th Dan)
// Pre-1st Dan: 500ms
// 1st-10th Dan: interpolate from 500ms to 10ms
const getAnimationInterval = () => {
if (currentIndex < 10) {
// Kyu levels: constant 500ms
if (currentIndex < 11) {
// Kyu levels and Pre-1st Dan: constant 500ms
return 500
}
// Dan levels: speed up from 500ms to 50ms
// Index 10 (Pre-1st Dan) → 500ms
// Index 20 (10th Dan) → 50ms
const danProgress = (currentIndex - 10) / 10 // 0.0 to 1.0
return 500 - danProgress * 450 // 500ms down to 50ms
// 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()
@@ -575,12 +587,11 @@ export default function LevelsPage() {
</div>
</div>
{/* Abacus Display */}
{/* Abacus Display with Level Details */}
<div
className={css({
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
gap: '4',
p: '6',
bg: 'rgba(0, 0, 0, 0.3)',
rounded: 'lg',
@@ -590,19 +601,74 @@ export default function LevelsPage() {
flex: 1,
})}
>
<animated.div
style={{
transform: animatedProps.scaleFactor.to((s) => `scale(${s / scaleFactor})`),
}}
{/* Level Details (only for Kyu levels) */}
{currentLevel.type === 'kyu' &&
(() => {
const detailsKey = getLevelDetailsKey(currentLevel.level)
const detailsText = detailsKey
? kyuLevelDetails[detailsKey as keyof typeof kyuLevelDetails]
: null
// Calculate responsive font size based on digits
// More digits = larger abacus = less space for details
const getFontSize = () => {
if (currentLevel.digits <= 3) return 'sm' // 10th-8th Kyu
if (currentLevel.digits <= 6) return 'xs' // 7th-5th Kyu
return '2xs' // 4th-1st Kyu
}
return detailsText ? (
<div
className={css({
flex: '0 0 auto',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
pr: '4',
borderRight: '1px solid',
borderColor: 'gray.600',
maxW: '280px',
})}
>
<pre
className={css({
fontFamily: 'mono',
fontSize: getFontSize(),
color: 'gray.300',
lineHeight: '1.5',
whiteSpace: 'pre-wrap',
wordWrap: 'break-word',
})}
>
{detailsText}
</pre>
</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,
})}
>
<AbacusReact
value={displayValue}
columns={currentLevel.digits}
scaleFactor={scaleFactor}
showNumbers={true}
customStyles={darkStyles}
/>
</animated.div>
<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 */}

View File

@@ -0,0 +1,147 @@
/**
* Detailed requirements for each Kyu level in the Soroban certification system
* Source: shuzan.jp
*/
export const kyuLevelDetails = {
'10-kyu': `+ / :
• 2-digit, 5 rows, 10 chars
×:
• 3 digits total (20 problems)
Exam: 20 min
Pass: ≥60/200 points`,
'9-kyu': `+ / :
• 2-digit, 5 rows, 10 chars
×:
• 3 digits total (20 problems)
Exam: 20 min
Pass: ≥120/200 points`,
'8-kyu': `+ / :
• 2-digit, 8 rows, 16 chars
×:
• 4 digits total (10 problems)
÷:
• 3 digits total (10 problems)
Exam: 20 min | Pass: ≥120/200`,
'7-kyu': `+ / :
• 2-digit, 10 rows, 20 chars
×:
• 4 digits total (10 problems)
÷:
• 4 digits total (10 problems)
Exam: 20 min | Pass: ≥120/200`,
'6-kyu': `+ / :
• 10 rows, 30 chars
×:
• 5 digits total (20 problems)
÷:
• 4 digits total (20 problems)
Exam: 30 min | Pass: ≥210/300`,
'5-kyu': `+ / :
• 10 rows, 40 chars
×:
• 6 digits total (20 problems)
÷:
• 5 digits total (20 problems)
Exam: 30 min | Pass: ≥210/300`,
'4-kyu': `+ / :
• 10 rows, 50 chars
×:
• 7 digits total (20 problems)
÷:
• 6 digits total (20 problems)
Exam: 30 min | Pass: ≥210/300`,
'Pre-3-kyu': `+ / :
• 10 rows, 50-60 chars (10 problems)
×:
• 7 digits total (20 problems)
÷:
• 6 digits total (20 problems)
Exam: 30 min | Pass: ≥240/300`,
'3-kyu': `+ / :
• 10 rows, 60 chars
×:
• 7 digits total (20 problems)
÷:
• 6 digits total (20 problems)
Exam: 30 min | Pass: ≥240/300`,
'Pre-2-kyu': `+ / :
• 10 rows, 70 chars
×:
• 8 digits total (20 problems)
÷:
• 7 digits total (20 problems)
Exam: 30 min | Pass: ≥240/300`,
'2-kyu': `+ / :
• 10 rows, 80 chars
×:
• 9 digits total (20 problems)
÷:
• 8 digits total (20 problems)
Exam: 30 min | Pass: ≥240/300`,
'Pre-1-kyu': `+ / :
• 10 rows, 90 chars
×:
• 10 digits total (20 problems)
÷:
• 9 digits total (20 problems)
Exam: 30 min | Pass: ≥240/300`,
'1-kyu': `+ / :
• 10 rows, 100 chars
×:
• 11 digits total (20 problems)
÷:
• 10 digits total (20 problems)
Exam: 30 min | Pass: ≥240/300`,
} as const
export type KyuLevel = keyof typeof kyuLevelDetails

View File

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