soroban-abacus-flashcards/packages/abacus-react/ENHANCEMENT_PLAN.md

440 lines
12 KiB
Markdown

# Abacus-React Feature Enhancement Plan
## Executive Summary
The web application has developed numerous custom patterns and workarounds for styling, layout, and interactions with the abacus component. These patterns reveal gaps in the abacus-react API that, if addressed, would significantly improve developer experience and reduce code duplication across the application.
## Priority 1: Critical Features (High Impact, High Frequency)
### 1. **Inline "Mini Abacus" Component**
**Location**: `apps/web/src/app/arcade/complement-race/components/AbacusTarget.tsx`
**Current Implementation**:
```tsx
<AbacusReact
value={number}
columns={1}
interactive={false}
showNumbers={false}
hideInactiveBeads={true}
scaleFactor={0.72}
customStyles={{
columnPosts: { opacity: 0 },
}}
/>
```
**Problem**: Creating an inline mini-abacus for displaying single digits requires multiple props and style overrides. This pattern appears throughout game UIs.
**Proposed Solution**: Add a `variant` prop with preset configurations:
```tsx
// Native API proposal
<AbacusReact
value={7}
variant="inline-digit"
// Automatically sets: columns=1, hideInactiveBeads, transparent frame, optimal scaleFactor
/>
// Or more granular:
<AbacusReact
value={7}
compact={true} // Removes frame, optimizes spacing
frameVisible={false} // Hide posts and bar
/>
```
**Benefits**:
- Single prop instead of 5+
- Consistent inline abacus appearance across the app
- Better semantic intent
---
### 2. **Theme-Aware Styling Presets**
**Locations**:
- `MyAbacus.tsx` (lines 60-85) - structural & trophy styles
- `HeroAbacus.tsx` (lines 20-32) - structural styles
- `LevelSliderDisplay.tsx` (lines 263-275) - dark theme styles
**Current Pattern**: Every component defines custom style objects for structural elements:
```tsx
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,
},
};
```
**Problem**: Manual style object creation for common themes is repetitive and error-prone.
**Proposed Solution**: Add theme presets to abacus-react:
```tsx
// Native API proposal
<AbacusReact
value={123}
theme="dark" // or "light", "translucent", "solid", "trophy"
/>;
// Or expose theme constants
import { ABACUS_THEMES } from "@soroban/abacus-react";
<AbacusReact customStyles={ABACUS_THEMES.dark} />;
```
**Benefits**:
- Eliminates ~30 lines of style definitions per component
- Ensures visual consistency
- Makes theme switching trivial
---
### 3. **Scaling Containers & Responsive Layouts**
**Locations**:
- `HeroAbacus.tsx` (lines 133-138) - manual scale transforms
- `MyAbacus.tsx` (lines 214-218) - responsive scale values
- `LevelSliderDisplay.tsx` (lines 370-379) - dynamic scale calculation
**Current Pattern**: Components manually wrap abacus in transform containers:
```tsx
<div
style={{
transform: "scale(3.5)",
transformOrigin: "center center",
}}
>
<AbacusReact value={1234} columns={4} />
</div>
```
**Problem**: Manual transform handling requires extra DOM nesting, breaks click boundaries, and makes centering complex.
**Proposed Solution**: Enhanced `scaleFactor` with responsive breakpoints:
```tsx
// Native API proposal
<AbacusReact
value={1234}
scaleFactor={{ base: 2.5, md: 3.5, lg: 4.5 }} // Responsive
scaleOrigin="center" // Handle transform origin
scaleContainer={true} // Apply correct boundaries for interaction
/>
```
**Benefits**:
- Eliminates wrapper divs
- Proper click/hover boundaries
- Built-in responsive scaling
---
## Priority 2: Developer Experience Improvements
### 4. **Bead Diff Calculation System**
**Location**: `apps/web/src/utils/beadDiff.ts` (285 lines) + `abacusInstructionGenerator.ts` (400+ lines)
**Current Implementation**: Complex utilities to calculate which beads need to move between states:
```tsx
// Current external pattern
import { calculateBeadDiffFromValues } from "@/utils/beadDiff";
const diff = calculateBeadDiffFromValues(fromValue, toValue);
const stepBeadHighlights = diff.changes.map((change) => ({
placeValue: change.placeValue,
beadType: change.beadType,
direction: change.direction,
// ...
}));
```
**Problem**: Tutorial/game developers need to calculate bead movements manually. This core logic belongs in abacus-react.
**Proposed Solution**: Add a diff calculation hook:
```tsx
// Native API proposal
import { useAbacusDiff } from "@soroban/abacus-react";
function Tutorial() {
const diff = useAbacusDiff(startValue, targetValue);
return (
<AbacusReact
value={currentValue}
stepBeadHighlights={diff.highlights} // Generated by hook
// diff also includes: instructions, order, validation
/>
);
}
```
**Benefits**:
- Centralizes "diff" algorithm
- Eliminates ~500 lines of application code
- Better tested and maintained
---
### 5. **Tutorial/Step Context Provider**
**Location**: `apps/web/src/components/tutorial/TutorialContext.tsx`
**Current Pattern**: Apps need to implement complex state management for multi-step tutorial flows with reducer patterns, event tracking, and error handling.
**Problem**: Tutorial infrastructure is duplicated across components. The logic for tracking progress through abacus instruction steps is tightly coupled to application code.
**Proposed Solution**: Add optional tutorial/stepper context to abacus-react:
```tsx
// Native API proposal
import { AbacusReact, AbacusTutorial } from "@soroban/abacus-react";
<AbacusTutorial
steps={[
{ from: 0, to: 5, instruction: "Add 5" },
{ from: 5, to: 15, instruction: "Add 10" },
]}
onStepComplete={(step) => {
/* analytics */
}}
onComplete={() => {
/* celebration */
}}
>
<AbacusReact />
</AbacusTutorial>;
```
**Benefits**:
- Reusable tutorial infrastructure
- Built-in progress tracking and validation
- Could power educational features across projects
---
## Priority 3: Nice-to-Have Enhancements
### 6. **Animation Speed Configuration**
**Location**: `LevelSliderDisplay.tsx` (lines 306-345)
**Current Pattern**: Applications control animation speed by rapidly changing the value prop:
```tsx
const intervalMs = 500 - danProgress * 490; // 500ms down to 10ms
setInterval(() => {
setAnimatedDigits((prev) => {
// Rapidly change digits to simulate calculation
});
}, intervalMs);
```
**Problem**: "Rapid calculation" animation requires external interval management.
**Proposed Solution**: Add animation speed prop:
```tsx
// Native API proposal
<AbacusReact
value={calculatingValue}
animationSpeed="fast" // or "normal", "slow", or ms number
autoAnimate={true} // Animate value prop changes automatically
/>
```
**Benefits**:
- Smoother animations with internal management
- Consistent timing across the app
---
### 7. **Draggable/Positionable Abacus Cards**
**Location**: `InteractiveFlashcards.tsx`
**Current Pattern**: Complex drag-and-drop implementation wrapped around each AbacusReact instance with pointer capture, offset tracking, and rotation.
**Problem**: Making abacus instances draggable requires significant boilerplate.
**Proposed Solution**: This is probably too specific to remain external. However, a ref-based API to get bounding boxes would help:
```tsx
// Possible improvement
const abacusRef = useAbacusRef()
<AbacusReact ref={abacusRef} />
// abacusRef.current.getBoundingBox() for drag calculations
```
---
### 8. **Column Highlighting for Multi-Step Problems**
**Location**: Tutorial system extensively
**Current Pattern**: Manual column highlighting based on place values with custom overlay positioning logic.
**Problem**: Highlighting specific columns (e.g., "the tens column") requires external overlay management.
**Proposed Solution**: Add native column highlighting:
```tsx
// Native API proposal
<AbacusReact
value={123}
highlightColumns={[1]} // Highlight tens column
columnLabels={["ones", "tens", "hundreds"]} // Optional labels
/>
```
---
## Priority 4: Documentation & Exports
### 9. **Utility Functions & Types**
**Current State**: Apps re-implement utilities for working with abacus states:
- `numberToAbacusState()` - convert numbers to bead states
- `calculateBeadChanges()` - diff algorithm
- `ValidPlaceValues` type - imported but limited
**Proposed Solution**: Export more utilities from abacus-react:
```tsx
// Expanded exports
export {
// Utilities
numberToAbacusState,
abacusStateToNumber,
calculateBeadDiff,
validateAbacusValue,
// Types
AbacusState,
BeadState,
PlaceValue,
// Hooks
useAbacusDiff,
useAbacusValidation,
useAbacusState,
};
```
---
## Implementation Roadmap
### Phase 1 (Immediate) ✅ COMPLETED
1. ✅ Add `frameVisible={false}` prop
2. ✅ Add `compact` prop/variant
3. ✅ Export theme presets (ABACUS_THEMES constant)
### Phase 2 (Short-term) ✅ COMPLETED
4. ⏸️ Enhanced `scaleFactor` with responsive object support (DEFERRED - too complex, low priority)
5. ✅ Export utility functions (numberToAbacusState, calculateBeadDiff, etc.)
### Phase 3 (Medium-term) ✅ COMPLETED
6. ✅ Add `useAbacusDiff` hook
7. ✅ Add native column highlighting with `highlightColumns` and `columnLabels` props
### Phase 4 (Long-term - Future)
8. 📋 Consider tutorial context provider (needs more research)
9. 📋 Animation speed controls
## Completed Features Summary
### New Props
- `frameVisible?: boolean` - Show/hide column posts and reckoning bar
- `compact?: boolean` - Compact layout for inline display (implies frameVisible=false)
- `highlightColumns?: number[]` - Highlight specific columns by index
- `columnLabels?: string[]` - Optional labels for columns
### New Exports
- `ABACUS_THEMES` - Pre-defined theme presets (light, dark, trophy, translucent, solid, traditional)
- `AbacusThemeName` type - TypeScript type for theme names
### New Utility Functions
- `numberToAbacusState(value, maxPlaces)` - Convert number to bead positions
- `abacusStateToNumber(state)` - Convert bead positions to number
- `calculateBeadChanges(startState, targetState)` - Calculate bead differences
- `calculateBeadDiff(fromState, toState)` - Full diff with order and directions
- `calculateBeadDiffFromValues(from, to, maxPlaces)` - Convenience wrapper
- `validateAbacusValue(value, maxPlaces)` - Validate number ranges
- `areStatesEqual(state1, state2)` - Compare states
### New Hooks
- `useAbacusDiff(fromValue, toValue, maxPlaces)` - Calculate bead differences for tutorials
- `useAbacusState(value, maxPlaces)` - Convert number to abacus state (memoized)
### New Types
- `BeadState` - Bead state in a single column
- `AbacusState` - Complete abacus state
- `BeadDiffResult` - Single bead movement result
- `BeadDiffOutput` - Complete diff output
- `PlaceValueBasedBead` - Internal place-value based bead type
---
## Metrics & Impact
**Code Reduction Estimate**:
- Eliminates ~800-1000 lines of repetitive application code
- Reduces component complexity by ~40% for tutorial/game components
**Developer Experience**:
- Faster onboarding for new features using abacus
- More consistent UX across application
- Better TypeScript support and autocomplete
**Maintenance**:
- Centralized logic easier to test and debug
- Single source of truth for abacus behavior
- Easier to add new features (e.g., sound effects for different themes)
---
## Questions for Discussion
1. Should we split these into separate packages (e.g., `@soroban/abacus-tutorial`)?
2. Which theme presets should be included by default?
3. Should responsive scaling use CSS media queries or JS breakpoints?
4. How much tutorial logic belongs in the core library vs. app code?