fix: correct column indexing and add boundary checks for interactive abacus
- Fix column indexing bug where tens/ones columns were swapped - Add boundary checks to prevent values exceeding abacus capacity - Improve earth and heaven bead click logic with proper place value mapping 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
697552ecd9
commit
bbfb3614a2
|
|
@ -99,7 +99,8 @@
|
|||
"WebFetch(domain:www.radix-ui.com)",
|
||||
"Read(//Users/antialias/**)",
|
||||
"Bash(turbo run:*)",
|
||||
"Bash(npx turbo run:*)"
|
||||
"Bash(npx turbo run:*)",
|
||||
"Bash(open http://localhost:3003/guide)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
"@myriaddreamin/typst-ts-renderer": "0.6.1-rc3",
|
||||
"@myriaddreamin/typst-ts-web-compiler": "0.6.1-rc3",
|
||||
"@myriaddreamin/typst.ts": "0.6.1-rc3",
|
||||
"@number-flow/react": "^0.5.10",
|
||||
"@pandacss/dev": "^0.20.0",
|
||||
"@radix-ui/react-accordion": "^1.1.2",
|
||||
"@radix-ui/react-checkbox": "^1.0.4",
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ export function InteractiveAbacus({
|
|||
}: InteractiveAbacusProps) {
|
||||
const [currentValue, setCurrentValue] = useState(initialValue)
|
||||
const [isChanging, setIsChanging] = useState(false)
|
||||
const [previousValue, setPreviousValue] = useState(initialValue)
|
||||
const svgRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
// Animated value display
|
||||
|
|
@ -39,6 +40,13 @@ export function InteractiveAbacus({
|
|||
config: { tension: 400, friction: 25 }
|
||||
})
|
||||
|
||||
// Crossfade animation between old and new SVG states
|
||||
const crossfadeSpring = useSpring({
|
||||
opacity: isChanging ? 0.7 : 1,
|
||||
transform: isChanging ? 'scale(0.98)' : 'scale(1)',
|
||||
config: { tension: 300, friction: 30 }
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -60,12 +68,15 @@ export function InteractiveAbacus({
|
|||
|
||||
if (beadType === 'earth') {
|
||||
const position = parseInt(beadPosition || '0')
|
||||
const columnPower = Math.pow(10, beadColumn)
|
||||
const placeValue = columns - 1 - beadColumn
|
||||
const columnPower = Math.pow(10, placeValue)
|
||||
const currentDigit = Math.floor(currentValue / columnPower) % 10
|
||||
const heavenContribution = Math.floor(currentDigit / 5) * 5
|
||||
const earthContribution = currentDigit % 5
|
||||
console.log('Earth bead analysis:', {
|
||||
position,
|
||||
beadColumn,
|
||||
placeValue,
|
||||
columnPower,
|
||||
currentDigit,
|
||||
heavenContribution,
|
||||
|
|
@ -75,20 +86,27 @@ export function InteractiveAbacus({
|
|||
|
||||
if (beadType === 'heaven') {
|
||||
// Toggle heaven bead (worth 5)
|
||||
const columnPower = Math.pow(10, beadColumn)
|
||||
// Column indexing: 0=leftmost, but place values are rightmost=ones
|
||||
// For 3 columns: col 0=hundreds(10^2), col 1=tens(10^1), col 2=ones(10^0)
|
||||
const placeValue = columns - 1 - beadColumn
|
||||
const columnPower = Math.pow(10, placeValue)
|
||||
const heavenValue = 5 * columnPower
|
||||
|
||||
const maxValue = Math.pow(10, columns) - 1
|
||||
|
||||
if (isActive) {
|
||||
// Deactivate heaven bead - subtract 5 from this column
|
||||
setCurrentValue(prev => Math.max(0, prev - heavenValue))
|
||||
} else {
|
||||
// Activate heaven bead - add 5 to this column
|
||||
setCurrentValue(prev => prev + heavenValue)
|
||||
setCurrentValue(prev => Math.min(prev + heavenValue, maxValue))
|
||||
}
|
||||
} else if (beadType === 'earth' && beadPosition) {
|
||||
// Toggle earth bead (worth 1 each)
|
||||
const position = parseInt(beadPosition) // 0-3 where 0 is top (closest to bar), 3 is bottom
|
||||
const columnPower = Math.pow(10, beadColumn)
|
||||
// Column indexing: 0=leftmost, but place values are rightmost=ones
|
||||
const placeValue = columns - 1 - beadColumn
|
||||
const columnPower = Math.pow(10, placeValue)
|
||||
|
||||
// Calculate current digit in this column
|
||||
const currentDigit = Math.floor(currentValue / columnPower) % 10
|
||||
|
|
@ -129,12 +147,19 @@ export function InteractiveAbacus({
|
|||
const columnContribution = Math.floor(currentValue / columnPower) % 10 * columnPower
|
||||
const newValue = currentValue - columnContribution + (newDigit * columnPower)
|
||||
|
||||
setCurrentValue(Math.max(0, newValue))
|
||||
// Ensure value doesn't exceed maximum for this number of columns
|
||||
const maxValue = Math.pow(10, columns) - 1
|
||||
setCurrentValue(Math.max(0, Math.min(newValue, maxValue)))
|
||||
}
|
||||
|
||||
// Visual feedback
|
||||
// Visual feedback with extended timing for smoother transition
|
||||
setIsChanging(true)
|
||||
setTimeout(() => setIsChanging(false), 150)
|
||||
|
||||
// Update previous value for crossfade effect
|
||||
setPreviousValue(currentValue)
|
||||
|
||||
// Extended timing to allow for smoother crossfade
|
||||
setTimeout(() => setIsChanging(false), 300)
|
||||
}, [currentValue])
|
||||
|
||||
// Add click event listener for bead interactions
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ importers:
|
|||
'@myriaddreamin/typst.ts':
|
||||
specifier: 0.6.1-rc3
|
||||
version: 0.6.1-rc3(@myriaddreamin/typst-ts-renderer@0.6.1-rc3)(@myriaddreamin/typst-ts-web-compiler@0.6.1-rc3)
|
||||
'@number-flow/react':
|
||||
specifier: ^0.5.10
|
||||
version: 0.5.10(react-dom@18.0.0)(react@18.0.0)
|
||||
'@pandacss/dev':
|
||||
specifier: ^0.20.0
|
||||
version: 0.20.1(jsdom@27.0.0)(typescript@5.0.2)
|
||||
|
|
@ -1377,6 +1380,18 @@ packages:
|
|||
engines: {node: '>=12.4.0'}
|
||||
dev: true
|
||||
|
||||
/@number-flow/react@0.5.10(react-dom@18.0.0)(react@18.0.0):
|
||||
resolution: {integrity: sha512-a8Wh5eNITn7Km4xbddAH7QH8eNmnduR6k34ER1hkHSGO4H2yU1DDnuAWLQM99vciGInFODemSc0tdxrXkJEpbA==}
|
||||
peerDependencies:
|
||||
react: ^18 || ^19
|
||||
react-dom: ^18 || ^19
|
||||
dependencies:
|
||||
esm-env: 1.2.2
|
||||
number-flow: 0.5.8
|
||||
react: 18.0.0
|
||||
react-dom: 18.0.0(react@18.0.0)
|
||||
dev: false
|
||||
|
||||
/@pandacss/config@0.20.1:
|
||||
resolution: {integrity: sha512-RG+WWK2NAZhmikChYsER61YIHiR4IsLH52guJdhuerk+nT5dpSrs3RkGM5F8Fs18Pkcj+gWwcS+g+g41ictf1w==}
|
||||
dependencies:
|
||||
|
|
@ -4388,6 +4403,10 @@ packages:
|
|||
- supports-color
|
||||
dev: true
|
||||
|
||||
/esm-env@1.2.2:
|
||||
resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==}
|
||||
dev: false
|
||||
|
||||
/espree@9.6.1:
|
||||
resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
|
|
@ -5618,6 +5637,12 @@ packages:
|
|||
path-key: 4.0.0
|
||||
dev: true
|
||||
|
||||
/number-flow@0.5.8:
|
||||
resolution: {integrity: sha512-FPr1DumWyGi5Nucoug14bC6xEz70A1TnhgSHhKyfqjgji2SOTz+iLJxKtv37N5JyJbteGYCm6NQ9p1O4KZ7iiA==}
|
||||
dependencies:
|
||||
esm-env: 1.2.2
|
||||
dev: false
|
||||
|
||||
/object-assign@4.1.1:
|
||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
|
|
|||
Loading…
Reference in New Issue