Compare commits

...

12 Commits

Author SHA1 Message Date
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
3 changed files with 131 additions and 13 deletions

View File

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

View File

@@ -1,6 +1,6 @@
'use client'
import { useState } from 'react'
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'
@@ -183,8 +183,84 @@ const allLevels = [
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
// 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)
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)
@@ -205,17 +281,12 @@ export default function LevelsPage() {
config: { duration: 120 },
})
// Generate an interesting non-zero number to display on the abacus
// Use a suffix pattern so rightmost digits stay constant as columns increase
// This prevents beads from shifting: ones always 9, tens always 8, etc.
const digitPattern = '123456789'
// Use BigInt for numbers > 15 digits (Dan levels with 30 columns)
const repeatedPattern = digitPattern.repeat(Math.ceil(currentLevel.digits / digitPattern.length))
const digitString = repeatedPattern.slice(-currentLevel.digits)
// Convert animated digits to a number/BigInt for the abacus display
// Use BigInt for large numbers to get full 30-digit precision
const displayValue =
currentLevel.digits > 15 ? BigInt(digitString) : Number.parseInt(digitString, 10)
animatedDigits.length > 15
? BigInt(animatedDigits || '0')
: Number.parseInt(animatedDigits || '0', 10)
// Dark theme styles matching the homepage
const darkStyles = {
@@ -299,6 +370,8 @@ export default function LevelsPage() {
<section className={stack({ gap: '8' })}>
{/* Current Level Display */}
<div
onMouseEnter={() => setIsPaneHovered(true)}
onMouseLeave={() => setIsPaneHovered(false)}
className={css({
bg: 'transparent',
border: '2px solid',
@@ -331,7 +404,7 @@ export default function LevelsPage() {
display: 'flex',
alignItems: 'center',
pointerEvents: 'none',
px: '90px', // Half of bead width (180px / 2)
px: '0', // Use full width for tick spacing
})}
>
<div
@@ -367,6 +440,9 @@ export default function LevelsPage() {
min={0}
max={allLevels.length - 1}
step={1}
onMouseMove={handleSliderHover}
onMouseEnter={() => setIsHovering(true)}
onMouseLeave={() => setIsHovering(false)}
className={css({
position: 'relative',
display: 'flex',
@@ -437,7 +513,7 @@ export default function LevelsPage() {
<div
className={css({
position: 'absolute',
bottom: '-60px',
bottom: '-80px',
left: '50%',
transform: 'translateX(-50%)',
textAlign: 'center',

View File

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