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>
This commit is contained in:
Thomas Hallock 2025-10-20 10:57:12 -05:00
parent 92fedb698d
commit 9dff3e7b7b
1 changed files with 20 additions and 3 deletions

View File

@ -198,8 +198,25 @@ export default function LevelsPage() {
setAnimatedDigits(generateRandomDigits(currentLevel.digits))
}, [currentLevel.digits])
// Animate abacus calculations every 0.5 seconds
// Animate abacus calculations - speed increases with Dan level
useEffect(() => {
// Calculate animation speed based on level
// Kyu levels: 500ms
// Dan levels: interpolate from 500ms (Pre-1st Dan) to 50ms (10th Dan)
const getAnimationInterval = () => {
if (currentIndex < 10) {
// Kyu levels: 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
}
const intervalMs = getAnimationInterval()
const interval = setInterval(() => {
setAnimatedDigits((prev) => {
const digits = prev.split('').map(Number)
@ -216,10 +233,10 @@ export default function LevelsPage() {
return digits.join('')
})
}, 500)
}, intervalMs)
return () => clearInterval(interval)
}, [])
}, [currentIndex])
// Auto-advance slider position every 3 seconds (unless pane is hovered)
useEffect(() => {