Commit Graph

1464 Commits

Author SHA1 Message Date
Thomas Hallock fde5ae9164 feat: add function-based custom bead rendering and HTTP status code easter eggs
Add dynamic custom bead rendering system that allows beads to change appearance
based on their context (active state, position, place value, type, etc.).

Custom Bead Features:
- Add emoji-function, image-function, and svg-function types
- Functions receive CustomBeadContext with bead state and style info
- Support for dynamic rendering based on: active state, position, place value,
  bead type (heaven/earth), color, and size
- Enables creative visualizations like traffic lights, themed symbols, etc.

404 Page Easter Eggs:
- Create interactive 404 page with manipulable abacus
- Add 14 HTTP status code easter eggs (200, 201, 301, 400, 401, 403, 418,
  420, 451, 500, 503, 666, 777, 911)
- Each code triggers site-wide custom bead transformation
- Use function-based rendering for variety (different emojis per bead
  position/state)
- Easter eggs persist until page reload via global AbacusDisplayContext

Storybook Documentation:
- Add comprehensive custom bead stories showing static and function-based usage
- Include examples: active/inactive states, heaven/earth types, place value
  colors, traffic lights, color theming
- Document CustomBeadContext API and usage patterns

Technical Implementation:
- Extend CustomBeadContent union type in AbacusContext
- Update AbacusStaticBead and AbacusAnimatedBead to handle function types
- Pass bead context (type, value, active, position, placeValue, color, size)
  to custom render functions
- Maintain consistency across static (SSR) and animated (client) rendering

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 14:28:58 -06:00
Thomas Hallock 8407b070f9 feat(worksheets): filter operator-specific scaffolds from preset summaries
When displaying difficulty preset descriptions in dropdown, filter out
scaffolds that don't apply to the current operator:

- Addition-only: hide borrowNotation, borrowingHints from summaries
- Subtraction-only: hide carryBoxes, tenFrames from summaries
- Mixed: show all scaffolds

Updated function:
- getScaffoldingSummary(): added operator parameter with conditional
  scaffold checking based on operator type

Fixes issue where preset dropdown showed subtraction-specific scaffolds
(borrow notation, borrowing hints) even for addition-only worksheets.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 14:28:58 -06:00
Thomas Hallock cace1c75c6 feat(worksheets): filter operator-specific scaffolds from difficulty change descriptions
When adjusting difficulty via Make Harder/Easier buttons, filter out
scaffolds that don't apply to the current operator:

- Addition-only: hide borrowNotation, borrowingHints from descriptions
- Subtraction-only: hide carryBoxes, tenFrames from descriptions
- Mixed: show all scaffolds

Updated functions:
- describeScaffoldingChange(): added operator parameter with filtering logic
- makeHarder(): passes operator to describeScaffoldingChange
- makeEasier(): passes operator to describeScaffoldingChange
- SmartModeControls: passes formState.operator to both functions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 14:28:58 -06:00
Thomas Hallock d23b606642 fix(worksheets): Add "Practice" difficulty profile for scaffolded regrouping mastery
CRITICAL PEDAGOGICAL FIX: The difficulty progression was removing scaffolding
at the same time regrouping was being introduced, which is backwards!

The Problem:
- Beginner: 0% regrouping, 100% scaffolding ✓
- Early Learner: 25% regrouping, 100% scaffolding ✓
- Intermediate: 75% regrouping, 50% scaffolding ✗ WRONG!
- Advanced/Expert: 90% regrouping, 0% scaffolding ✗ WRONG!

Students were losing scaffolds (answer boxes, place value colors, ten-frames)
exactly when they needed them most - during intensive regrouping practice.

The Fix:
Added new "Practice" difficulty profile between Early Learner and Intermediate:

- Beginner: 0% regrouping, 100% scaffolding (learn structure)
- Early Learner: 25% regrouping, 100% scaffolding (introduce regrouping)
- **Practice: 75% regrouping, 100% scaffolding** ← NEW! (master WITH support)
- Intermediate: 75% regrouping, 50% scaffolding (begin removing support)
- Advanced/Expert: 90% regrouping, 0% scaffolding (full mastery)

Practice Profile Details:
- regrouping: { pAllStart: 0.25, pAnyStart: 0.75 } (same as Intermediate)
- carryBoxes: 'whenRegrouping' (show borrow/carry boxes when needed)
- answerBoxes: 'always' (keep guiding placement during intensive practice)
- placeValueColors: 'always' (keep visual support)
- tenFrames: 'whenRegrouping' (visual aid for regrouping)

Pedagogical Rationale:
Students need a "plateau phase" where they practice regrouping frequently
WITH full scaffolding support before we start removing training wheels.

This is especially critical for subtraction borrowing:
- First encounter borrowing with low frequency (Early Learner)
- Then practice borrowing intensively WITH scaffolds (Practice)
- Then gradually remove scaffolds as mastery develops (Intermediate → Expert)

Impact:
- Teachers selecting "Practice" mode get frequent regrouping with full support
- Smart difficulty progression no longer removes scaffolds prematurely
- Addresses user feedback: "we start turning off scaffolding for subtraction
  as soon as we introduce regrouping, which defeats the whole point"

Updated DIFFICULTY_PROGRESSION:
['beginner', 'earlyLearner', 'practice', 'intermediate', 'advanced', 'expert']

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 14:28:58 -06:00
Thomas Hallock 693b679965 feat: add theme support to worksheet preview
Add light/dark mode support to WorksheetPreview component:
- Preview title and subtitle text adapt to theme
- SVG preview container uses themed background
- Pagination text adjusts for readability
- Info box uses blue theme variants (light or dark)
- Maintains brand button colors across themes
- Pass isDark through Suspense boundary

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 13:11:41 -06:00
Thomas Hallock e38775b991 feat: add theme support to orientation and generate panels
Add light/dark mode support to OrientationPanel and GenerateButton:
- OrientationPanel: themed backgrounds for all sections
- Orientation buttons adapt to theme (selected/unselected states)
- Page number buttons use themed backgrounds
- Problems per page dropdown has themed content
- Dropdown items and labels adjust for readability
- Total badge remains consistent (brand colors)
- GenerateButton panel uses themed background

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 13:11:41 -06:00
Thomas Hallock c8684213fa feat: add theme support to config panel components
Add light/dark mode support to all config panel components:
- StudentNameInput: themed input backgrounds and borders
- DigitRangeSection: themed section backgrounds and text
- OperatorSection: themed button states
- ModeSelector: themed mode selection cards
- ProgressiveDifficultyToggle: themed switch and backgrounds
- ToggleOption: themed toggle containers and text
- SmartModeControls & ManualModeControls: pass isDark prop through

All components now respond to light/dark theme with appropriate
backgrounds, borders, and text colors for optimal readability.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 13:11:41 -06:00
Thomas Hallock 5c14925d7d feat: add theme support to worksheet page container
Add light/dark mode support to AdditionWorksheetClient:
- Page background adapts to theme
- Header text colors adjust for readability
- Card panels use theme-appropriate backgrounds
- Settings status messages use themed colors
- Pass isDark prop to all child components

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 13:11:41 -06:00
Thomas Hallock 8d8e55d5c4 fix(worksheets): Fix subtraction regrouping frequency bug
CRITICAL BUG FIX: Subtraction problems weren't generating with expected
borrowing frequency when pAllStart/pAnyStart were set to 100%.

Root Cause:
The old `generateBothBorrow()` used naive digit comparison (digitM < digitS)
to count borrows, which:
1. Doesn't account for cascading borrows across zeros (e.g., 100 - 1)
2. Returns ZERO problems for 2-digit numbers (mathematically impossible
   to have both digits show digitM < digitS without negative result)

When user set regrouping to 100%, generator tried to create "both" problems
but failed every time, falling back to random problems or duplicates.

Fixes:
1. Added `countBorrows()` function that simulates actual subtraction algorithm
   - Tracks borrow operations through place values
   - Counts cascading borrows across zeros correctly
   - Example: 100 - 1 = 2 borrows (hundreds → tens → ones)

2. Updated `generateBothBorrow()` to:
   - Fall back to ones-only borrowing for 1-2 digit ranges (impossible to get 2+ borrows)
   - Favor higher digit counts (3+) when possible
   - Use correct borrow counting via `countBorrows()`

3. Changed fallback from [93, 57] (1 borrow) to [100, 1] or [534, 178] (2+ borrows)

Impact:
- 2-digit subtraction with pAll=100% now generates maximum difficulty (ones-only borrowing)
- 3+ digit subtraction with pAll=100% now correctly generates 2+ borrow problems
- User will see appropriate borrowing frequency at all difficulty settings

Test Examples:
- 52 - 17: 1 borrow ✓
- 100 - 1: 2 borrows ✓
- 534 - 178: 2 borrows ✓
- 1000 - 1: 3 borrows ✓

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 13:11:41 -06:00
Thomas Hallock 702c1c9af2 feat: add theme support to MyAbacus button
Add light/dark mode responsiveness to the floating MyAbacus button:
- Light mode: white background with golden accent border
- Dark mode: dark background with golden accent border
- Theme-aware box shadows for better visibility in each mode
- Maintains golden glow effect across both themes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 12:25:41 -06:00
Thomas Hallock 515e4c4f98 refactor: convert LanguageSelector to Radix UI with theme support
Replace native <select> element with Radix UI DropdownMenu and add
full light/dark theme support.

Changes:
- Replace native select with Radix UI DropdownMenu
- Add useTheme hook to detect current theme (light/dark)
- Theme-aware button styling:
  - Dark mode: gray.800 background with gray.700 border
  - Light mode: white background with gray.300 border
  - Fullscreen: black transparent with purple border
- Theme-aware dropdown content:
  - Dark mode: gray.900 background
  - Light mode: white background
  - Proper contrast for all text and hover states
- Add dropdown chevron icon that rotates when open
- Add checkmark (✓) for currently selected language
- Both variants (dropdown-item and inline) now use Radix UI
- Highlight selected language with background color
- Smooth transitions and proper hover states for both themes

Improves accessibility and consistency with other dropdowns.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 12:18:43 -06:00
Thomas Hallock 2e294ee820 feat: add theme support to abacus style dropdown
Make AbacusDisplayDropdown respond to light/dark mode.

Changes:
- Integrate useTheme hook to detect current theme
- Update button styling:
  - Dark mode: gray.800 background with gray.700 border
  - Light mode: white background with gray.200 border
- Update dropdown content styling:
  - Dark mode: gray.900 background with gray.800 border
  - Light mode: white background with gray.200 border
- Update all text colors for theme contrast:
  - Headers, labels, descriptions adapt to theme
- Update form controls for theme:
  - Switch backgrounds (gray.700 dark, gray.300 light)
  - Radio button borders and backgrounds
  - Volume slider track (gray.700 dark, gray.200 light)

All components now properly support light/dark themes while
maintaining existing fullscreen mode styling.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 12:17:26 -06:00
Thomas Hallock ab9272bee6 feat: add theme support to desktop hamburger menu
Make desktop dropdown menu and button respond to light/dark mode.

Changes:
- Desktop hamburger button background:
  - Dark mode: rgba(31, 41, 55, 0.9) with gray border
  - Light mode: white with light gray border
- Desktop hamburger button icon color:
  - Dark mode: light gray text
  - Light mode: dark gray text
- Desktop dropdown content background:
  - Dark mode: dark gray gradient
  - Light mode: white/light gray gradient
- Desktop dropdown box shadow:
  - Dark mode: darker shadow with purple border
  - Light mode: lighter shadow with subtle purple border

Maintains existing fullscreen mode styling (black background).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 12:14:29 -06:00
Thomas Hallock b57458b039 feat: implement two-column landscape layout with smart viewport-based flexbox
- Add two-column CSS Grid layout for landscape orientation (≥480px)
- Implement proper flexbox sizing chain to prevent scrolling:
  - Use minHeight: 0 and flex: 1 1 auto throughout container hierarchy
  - Only allow overflow on grid container when content truly exceeds viewport
- Compact spacing for better viewport fit:
  - Reduced padding: 8px 12px (from 16px 20px)
  - Reduced font size: 14px (from 18px)
  - Reduced icon size: 18px (from 24px)
  - Reduced gaps: 16px base, 20px landscape, 8px on short screens
- Responsive gap sizing based on viewport height
- Column 1: Navigation + Controls
- Column 2: Abacus Style + Language + Theme

The menu now uses proper CSS layout techniques to fit within viewport
bounds, only scrolling when content genuinely exceeds available space.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 12:11:49 -06:00
Thomas Hallock 3ad244f2d3 feat: make mobile menu more responsive with larger touch targets
Improve mobile full-screen menu to better utilize screen space with
larger, more touch-friendly UI elements.

Changes:
- Increase font sizes on mobile (18px links, 24px icons vs 14px/16px)
- Larger padding and gaps (16px-20px vs 10px-14px on desktop)
- Bigger border radius on mobile (12px vs 8px) for modern feel
- Increase section header spacing and size
- Add centered max-width container (600px) with top padding for close button
- Extract controlButtonStyle helper to avoid duplication
- Update all hover states to be theme-aware (light/dark)

Layout improvements:
- Content centered with max-width constraint
- Top padding (60px) to avoid close button overlap
- Consistent spacing between sections (20px margins)
- Icons scale appropriately (24px on mobile vs 16px desktop)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 12:11:49 -06:00
Thomas Hallock ea41b323d0 feat: add close button and theme support to mobile menu
Improve mobile full-screen menu UX with explicit close button and
light/dark theme responsiveness.

Changes:
- Add fixed close button (X) in top-right corner of mobile menu
- Integrate useTheme hook to detect current theme (light/dark)
- Theme-aware styling for menu background, text, and hover states
  - Dark mode: Dark gray gradients, light text
  - Light mode: Light gray gradients, dark text
- Pass resolvedTheme to MenuContent for consistent theming
- Update hover colors to match theme (purple variants)

UX improvements:
- Close button provides clear affordance for dismissing menu
- Clicking backdrop still closes menu as before
- Menu visually adapts to system/user theme preference

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 12:11:49 -06:00
Thomas Hallock 615cd28829 feat: implement full-screen mobile hamburger menu with portal
Refactor hamburger menu to use custom full-screen overlay on mobile
instead of Radix UI dropdown, fixing z-index stacking context issues.

Key changes:
- Extract MenuContent component for shared rendering logic between
  mobile and desktop versions
- Implement custom full-screen mobile menu with viewport detection
- Use React Portal to render mobile menu outside header's stacking
  context, ensuring it layers above hero abacus (z-index 9999 > 10)
- Desktop continues using Radix UI dropdown menu as before
- Mobile menu closes on navigation and backdrop click

Technical details:
- Header's opacity: 0.95 creates stacking context, constraining child
  z-indexes. Portal breaks out to document.body for global z-index.
- Conditional rendering based on viewport width (640px breakpoint)
- Shared MenuContent adapts rendering (plain divs vs Radix components)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 11:50:49 -06:00
Thomas Hallock 85db052f07 refactor(worksheets): Phase 5 - Final ConfigPanel cleanup
Final optimization of ConfigPanel.tsx:
- Removed all unused helper functions (getDefaultColsForProblemsPerPage, calculateDerivedState)
- Removed unused state variables (currentOrientation, currentProblemsPerPage, currentCols, currentPages)
- Removed unused handleDifficultyChange function (now in SmartModeControls)
- Removed all console.log debugging statements
- Added missing defaultAdditionConfig import
- ConfigPanel reduced to 105 lines (95.9% reduction from original 2550 lines)

Fixed ManualModeControls:
- Added missing Slider import from @radix-ui/react-slider
- Fixed runtime error: "ReferenceError: Slider is not defined"

Cleanup:
- Removed ConfigPanel.tsx.bak backup file
- Removed temporary shell scripts (/tmp/create_manual_mode.sh, /tmp/replace_manual_mode.sh)

ConfigPanel now contains ONLY:
- Props interface
- Mode switching handler (smart ↔ manual)
- Clean JSX rendering extracted components

All 5 phases of refactoring complete:
 Phase 1: Helper components (utils, SubOption, ToggleOption)
 Phase 2: Shared sections (StudentName, DigitRange, Operator, ProgressiveDifficulty)
 Phase 3: Smart Mode controls (1412 lines → SmartModeControls.tsx)
 Phase 4: Manual Mode controls (339 lines → ManualModeControls.tsx)
 Phase 5: Final cleanup (2550 lines → 105 lines)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 11:50:49 -06:00
Thomas Hallock 4cf6fcab15 refactor(worksheets): Phase 4 - Extract Manual Mode controls
Extract Manual Mode section from ConfigPanel into dedicated component:
- Created ManualModeControls.tsx (339 lines)
- Display options toggles with Check All/Uncheck All buttons
- Live preview panel (DisplayOptionsPreview)
- Regrouping frequency double-thumb slider
- ConfigPanel reduced to 207 lines (91.9% reduction from original 2550)

Removed from ConfigPanel:
- SubOption, ToggleOption, DisplayOptionsPreview imports
- defaultAdditionConfig import
- useTranslations hook and 't' variable
- Entire Manual Mode section (lines 210-531)

Fixed parsing error in ManualModeControls:
- Removed extra closing paren from fragment structure
- Formatted with biome

All display options now properly organized:
- Answer boxes, carry/borrow boxes, place value colors
- Ten-frames with sub-option for all problems
- Borrowing notation and hints (conditional on operator)
- Problem numbers, cell borders

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 11:50:49 -06:00
Thomas Hallock 76a6168b00 refactor(worksheets): extract Smart Mode controls (Phase 3 complete)
Extracted the massive Smart Mode section (~1384 lines) into a dedicated
SmartModeControls component. This section includes difficulty presets,
easier/harder buttons, and the interactive 2D difficulty visualization.

Extracted component:
- SmartModeControls.tsx: Complete smart mode UI (~1412 lines)
  - Difficulty preset dropdown
  - Make easier/harder buttons with alternative modes
  - Overall difficulty slider
  - 2D difficulty space visualizer with interactive SVG
  - Hover preview and snap-to-preset functionality

Changes:
- Removed unused imports from ConfigPanel (React, Slider, Tooltip, DropdownMenu, difficulty functions)
- Removed unused state variables (showDebugPlot, hoverPoint, hoverPreview)
- Updated ConfigPanel to import and use SmartModeControls
- File size reduced: 1942 → 534 lines (-1408 lines, 72.5% reduction!)

Total progress: 2550 → 534 lines (-2016 lines, 79.1% reduction)

Zero functionality change - all smart mode features work identically.
Phase 3 of 5 complete.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 11:50:49 -06:00
Thomas Hallock d27e2c03bd refactor(worksheets): extract shared ConfigPanel sections (Phase 2 complete)
Extracted all shared UI sections that appear in both smart and manual modes
to separate components for improved modularity and reusability.

Extracted components:
- DigitRangeSection.tsx: Digit range slider with tick marks (~170 lines)
- OperatorSection.tsx: Operator selection buttons (~120 lines)
- ProgressiveDifficultyToggle.tsx: Progressive difficulty toggle (~90 lines)

Changes:
- Removed unused imports (Slider, Switch - now in extracted components)
- Updated ConfigPanel.tsx to use new components
- File size reduced: 2286 → 1942 lines (-344 lines)

Total progress so far: 2550 → 1942 lines (-608 lines, 23.8% reduction)

Zero functionality change - all components work identically.
Phase 2 of 5 complete.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 11:50:49 -06:00
Thomas Hallock cbe29d5c54 refactor(worksheets): extract StudentNameInput component (Phase 2 - partial)
Extracted Student Name input field to separate component as part of Phase 2.

Changes:
- Created StudentNameInput.tsx component (32 lines)
- Updated ConfigPanel.tsx to use new component
- File size reduced: 2306 → 2286 lines (-20 lines)

Remaining Phase 2 work: Extract DigitRangeSection, OperatorSection, and ProgressiveDifficultyToggle components.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 11:50:49 -06:00
Thomas Hallock 3656800534 refactor(worksheets): extract ConfigPanel helper components (Phase 1)
Created config-panel/ subdirectory and extracted reusable UI components
from the monolithic 2550-line ConfigPanel.tsx file.

Extracted components:
- utils.tsx: getScaffoldingSummary() function
- SubOption.tsx: Nested toggle UI component
- ToggleOption.tsx: Main toggle option with description

Changes:
- Created src/app/create/worksheets/addition/components/config-panel/ directory
- Moved 3 helper functions/components to separate files (~240 lines)
- Updated ConfigPanel.tsx to import from new locations
- Removed unused imports (Checkbox, findNearestPreset)
- File size reduced: 2550 → 2306 lines (-244 lines)

Zero functionality change - all components work identically.
Part 1 of 5-phase refactoring plan.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 11:50:49 -06:00
Thomas Hallock 15bded1ab8 feat(worksheets): integrate subtraction scaffolding into smart difficulty mode
Previously, smart mode hardcoded showBorrowNotation and showBorrowingHints
to false. Now these fields are properly integrated into the display rules
system and scaffolding progression.

Changes:
- Extended DisplayRules interface with borrowNotation and borrowingHints fields
- Added fields to all 13 scaffolding levels and 5 difficulty profiles
- Updated config schemas (V2, V3, V4) with backward-compatible migrations
- Removed hardcoded false values in typstGenerator.ts
- Updated getScaffoldingSummary() to show new scaffolding aids
- Fixed typstGenerator subtraction parameter ordering (showCarryBoxes → showBorrowNotation)
- Fixed borrow hint text rendering (removed extra box wrapper)

Subtraction worksheets now receive the same conditional scaffolding
treatment as addition, with hints appearing at appropriate difficulty
levels and fading as students progress.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 11:50:49 -06:00
Thomas Hallock d05c6a8664 fix: use semantic tokens for nav bar transparent mode on hero
Replace hardcoded white colors in transparent nav mode with semantic tokens
that adapt to light/dark themes:

Transparent mode (hero overlay):
- Text: white → text.primary / text.secondary
- Background: rgba(255,255,255,0.08) → bg.subtle / bg.muted
- Borders: rgba(255,255,255,0.15) → border.subtle / border.default
- Hover: rgba(255,255,255,0.25) → interactive.hover

This fixes invisible white text on light backgrounds when viewing the
homepage hero in light mode.

Non-transparent mode (regular nav) remains unchanged with existing colors.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 10:09:46 -06:00
Thomas Hallock d9c58d74b5 Revert "fix: replace hardcoded colors with semantic tokens in nav bar links"
This reverts commit fc19a70a96.
2025-11-08 10:08:53 -06:00
Thomas Hallock fc19a70a96 fix: replace hardcoded colors with semantic tokens in nav bar links
Convert NavLink component from hardcoded light colors to semantic tokens:

- Inactive links: rgba(209, 213, 219, 0.9) → text.primary
- Active links: rgba(196, 181, 253, 1) → accent.emphasis
- Active background: rgba(139, 92, 246, 0.2) → accent.subtle
- Hover background: rgba(139, 92, 246, 0.25) → accent.muted

This fixes white/light gray text on white background in light mode for
Create, Guide, Games, and Blog navigation links.

Transparent mode (hero overlay) remains unchanged with white text.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 10:08:08 -06:00
Thomas Hallock ea10249e94 fix: add light/dark mode support to tutorial tooltips and decomposition UI
Use CSS light-dark() function to support both color schemes:

Decomposition reasoning tooltips:
- Background: white → dark in dark mode
- Borders: light gray → darker in dark mode
- Text: dark → light in dark mode
- Code blocks and steps: proper contrast in both modes

Tutorial player tooltips:
- Blue background adapts to theme
- Text remains white for good contrast

Fixes unreadable light text on light backgrounds in light mode.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 10:06:35 -06:00
Thomas Hallock e124096914 fix: replace hardcoded colors with semantic tokens in HomeBlogSection
Convert blog section from hardcoded rgba colors (dark mode only) to semantic
theme tokens that adapt to light/dark mode:

- text.primary, text.secondary, text.muted for content
- accent.subtle, accent.muted, accent.default for backgrounds/borders
- accent.emphasis for interactive text

This fixes unreadable white text on light backgrounds in light mode.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 10:02:46 -06:00
Thomas Hallock fcbf0f5421 fix(abacus-react): remove duplicate numeral rendering and fix dark mode colors
Two critical issues fixed:

1. **Duplicate numerals**: Both AbacusSVGRenderer and AbacusReact were rendering
   numerals when showNumbers={true}, causing two overlapping number displays.
   - Disabled SVG text numerals in AbacusSVGRenderer (line 436: added `false &&`)
   - NumberFlow provides better animated numerals, keep only those

2. **White numerals in dark mode**: NumberFlow components were inheriting CSS
   color from parent, turning white in dark mode (unreadable on light frames).
   - Added explicit color style to NumberFlow: uses themeAwareCustomStyles
   - Now consistently dark (rgba(0,0,0,0.8)) regardless of page theme

This was the root cause of the "white numerals everywhere" issue - the
NumberFlow components were inheriting dark mode CSS colors.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 09:43:18 -06:00
Thomas Hallock bc7ca12158 fix: add missing color definitions to example route
The example route was also missing generatePlaceValueColors() calls,
causing "unknown variable: color-ones" errors when rendering subtraction
examples. Added color definitions to both addition and subtraction templates.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 09:33:58 -06:00
Thomas Hallock 8b8dfeefbd fix: PDF generation now respects operator and digitRange settings
The PDF generation route was ignoring the operator and digitRange settings,
always generating 2-digit addition problems regardless of configuration.
The preview worked correctly but PDF generation was broken.

Changes:
- Add conditional logic to call appropriate problem generator based on operator
- Pass digitRange parameter to all problem generators
- Add generatePlaceValueColors() to Typst template for color definitions
- Import DisplayOptions type for internal use in typstHelpers

Fixes worksheet PDF generation for subtraction, mixed, and multi-digit problems.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 09:31:57 -06:00
Thomas Hallock a769fe1e20 refactor: complete subtraction modularization - 793 lines → modular structure
Major refactoring milestone: Successfully modularized subtraction problem
rendering from a monolithic 360-line function into focused, composable components.

File size reduction:
- typstHelpers.ts: 793 lines → 356 lines (55% reduction)
- Subtraction function: 360 lines → distributed across 6 focused files

New modular structure:
├── subtraction/
│   ├── problemStack.ts (120 lines) - Main composition function
│   ├── borrowBoxes.ts (94 lines) - Borrow boxes with hints/arrows
│   ├── minuendRow.ts (96 lines) - Top number with scratch boxes
│   ├── subtrahendRow.ts (75 lines) - Bottom number with − sign
│   └── answerRow.ts (126 lines) - Line, ten-frames, answer boxes
└── index.ts - Re-exports for backward compatibility

Benefits achieved:
 No file exceeds 130 lines (was 793 lines)
 Each component has single, clear responsibility
 Easier to locate and edit specific features
 Centralized constants (TYPST_CONSTANTS)
 Better separation of concerns
 Backward compatibility maintained via re-exports

Implementation details:
- Updated typstHelpers.ts to re-export from modular structure
- Removed old 360-line generateSubtractionProblemStackFunction
- All imports remain unchanged (backward compatible)
- No functional changes - pure refactoring

Next phase:
- Extract addition components (carry boxes, addend rows)
- Validate output matches current worksheets byte-for-byte
- Add unit tests for individual components

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 09:20:18 -06:00
Thomas Hallock b42daf9a4b refactor: begin modularizing typstHelpers.ts - extract shared components
Phase 1 of typstHelpers.ts refactoring (793 lines → modular structure)

Created new directory structure:
- typstHelpers/shared/ - Colors, helpers, types
- typstHelpers/addition/ - Addition-specific components (future)
- typstHelpers/subtraction/ - Subtraction-specific components

Extracted components:
- shared/colors.ts - Place value color definitions
- shared/types.ts - TypeScript types and constants
- shared/helpers.ts - Reusable Typst helpers (ten-frames, diagonal-split-box)
- subtraction/borrowBoxes.ts - Borrow boxes row rendering with hints/arrows

Benefits:
- Smaller, focused files (50-100 lines each vs 350+ line functions)
- Centralized constants (arrow positioning, stroke widths)
- Better separation of concerns
- Easier to locate and edit specific features

Next steps:
- Extract remaining subtraction rows (minuend, subtrahend, answer)
- Refactor main function to compose extracted components
- Maintain backward compatibility via facade pattern
- Validate output matches current worksheets byte-for-byte

See TYPST_HELPERS_REFACTOR_PLAN.md for complete plan.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 08:04:50 -06:00
Thomas Hallock b4586bac8e fix: disable place value colors in subtraction borrow boxes to fix arrow layering
The arrows in borrowing hints were being covered by the diagonal-split-box
colored backgrounds in adjacent cells. This occurred because Typst renders
elements in document order, and arrows placed inside colored boxes appear
below backgrounds from cells rendered later.

Solution: Disable place value colors in borrow boxes entirely. Borrow boxes
now always use stroke-only rendering (no colored backgrounds), which ensures
arrows are never covered. Place value colors still work everywhere else
(minuend, subtrahend, and answer rows).

This is simpler and more maintainable than complex double-render or
compositing approaches, and avoids the fundamental layering limitation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 08:00:55 -06:00
Thomas Hallock 5cb346deee fix: use dark gray for borrowing hints on colored backgrounds
Change arrow and text from white to gray.darken(40%) when place
value colors are enabled. This ensures visibility on all pastel
backgrounds (blue, green, yellow, pink, purple, peach).

Maintains consistency with non-colored version which already uses gray.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 08:00:55 -06:00
Thomas Hallock 3e1b51bd84 feat: handle cascading borrows in borrowing hints
Improve borrowing hints to properly show cascading borrows:
- Detect when borrowing from 0 (cascade situation)
- Show "10 - 1" for intermediate cascade steps
- Show "n - 1" for source non-zero digit
- Example: 300 - 157 shows "3 - 1" at hundreds, "10 - 1" at tens

This makes the hints pedagogically correct for all subtraction
cases, avoiding confusing "0 - 1" displays for young learners.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 08:00:55 -06:00
Thomas Hallock 112745ce16 feat: add smooth curved arrow for borrowing hints
Complete borrowing hints visualization with smooth bezier curve:
- Curve starts near "1" in borrow box (dx: 0.9, dy: 0.15)
- Smooth quadratic bezier with control point for natural flow
- Ends at arrowhead position (0.24, 0.70 relative)
- Small arrowhead (0.35x font size) at (0.96, 0.62)
- White curve on colored backgrounds, gray on plain
- Typst bezier syntax: vertex with relative control point

Visual guide shows "n − 1" with arrow pointing to borrowed 10s box.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 08:00:55 -06:00
Thomas Hallock b2f875c5a5 feat: implement borrowing hints arrow visualization
Add visual arrow connecting borrow box to borrowed 10s box:
- Straight diagonal line from top of borrow box
- Points to center of borrowed 10s box below
- White line (1.5pt) on colored backgrounds
- Gray line on non-colored backgrounds
- Coordinates: (0, 0) to (0.24×cellSize, 0.75×cellSize)

Arrow appears when showBorrowingHints toggle is enabled.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 08:00:55 -06:00
Thomas Hallock bdf28b21b2 fix: position arrowhead at endpoint and increase size
- Position arrowhead at (2.0 - 0.03, 1.0 - 0.05) to be at arrow endpoint
- Increase arrowhead size from 0.4x to 0.5x for better visibility
- Remove bold weight so it renders as solid triangle pointing down
2025-11-08 08:00:55 -06:00
Thomas Hallock fab1fb10b7 fix: arrow direction - go RIGHT to borrowed 10s box, not left
The borrowed 10s box is visually to the RIGHT (ones place is right of tens).
Changed anchor from 'top + right' to 'top + left' with dx offset to position
at the right edge of borrow box, then curve goes right and down to the
borrowed 10s box.
2025-11-08 08:00:55 -06:00
Thomas Hallock 9b4eb14aaa fix: use curved Bezier path for borrow arrow
Replace straight diagonal line with proper curved arrow:
- Starts at top-right corner of borrow box
- Curves with convex side on upper right (control point at 0.3x, 0.2y)
- Ends at top-center of borrowed 10s box (1.225x right, 1.0y down)
- Arrowhead positioned just above endpoint
- Path anchored to top-right of borrow box for correct positioning
2025-11-08 08:00:55 -06:00
Thomas Hallock a9319c3bd8 feat: add diagonal arrow from '1' to borrowed 10s box
Draw a diagonal line from the right of the '1' in 'n − 1' down to the
borrowed 10s box below. Arrow shows the flow of the borrowed 1 moving
to become 10 in the next column.

- Line starts at dx: 0.08in (right of '1')
- Line ends at full cell width/height (top of borrowed 10s box)
- Arrowhead (▼) placed at endpoint
- White line/arrow for colored backgrounds, gray for no-color mode
2025-11-08 08:00:55 -06:00
Thomas Hallock 232e1a2221 refactor: place 'n − 1 →' text inside borrow box at top
- Keep borrow box at full size (not 70%)
- Use place() to position hint text at top center of box
- Add white text with black stroke for contrast on colored backgrounds
- Gray text when colors are disabled for better visibility
2025-11-08 08:00:55 -06:00
Thomas Hallock b718994dab feat: add arrow from '1' in borrow hint pointing right
Replace 'n + 10' text inside borrowed 10s box with an arrow (→) after
the '1' in 'n − 1' that points toward the borrowed 10s box. This shows
the flow of the borrowed 1 moving to the next column.

- Made the '1' bold to emphasize it
- Added rightward arrow (→) after the 1
- Removed the 'n + 10' text from inside the borrowed 10s box
2025-11-08 08:00:55 -06:00
Thomas Hallock f5d3de2309 fix: reduce borrowing hint font size from 0.5x to 0.25x
The 'n − 1' text above borrow boxes was too large and getting clipped,
making the '1' invisible. Halving the font size should make it fit better.
2025-11-08 08:00:55 -06:00
Thomas Hallock cc54176cb1 fix: use numeric cellSize for borrow box sizing in hints
Change from cellSizeIn * 0.7 (which produces NaN since cellSizeIn is a string)
to cellSize * 0.7 with unit added inline. This fixes the Typst compilation error
when borrowing hints are enabled.
2025-11-08 08:00:55 -06:00
Thomas Hallock 89b8f98662 feat: implement borrowing hints visual guidance
Add visual hints when showBorrowingHints is enabled:
- Show "n − 1" calculation above borrow boxes (what to write after borrowing)
- Show "n + 10" inside borrowed 10s box (what value the digit becomes)
- Hints appear in gray text to distinguish from student work
- Font sizes scaled appropriately (0.5x for borrow box hints, 0.45x for borrowed 10s)

This provides step-by-step guidance for young students learning borrowing,
showing them exactly what calculations to perform and what to write in each box.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 08:00:55 -06:00
Thomas Hallock 74c67566d2 feat: add infrastructure for borrowing hints toggle
Add new showBorrowingHints toggle to guide students through borrowing:
- Add showBorrowingHints field to V4 manual config schema
- Add toggle to ConfigPanel UI (shows for subtraction/mixed only)
- Wire through validation, auto-save, preview, and example route
- Update typstGenerator and typstHelpers to accept parameter
- Default to false for backward compatibility

This commit adds the plumbing/infrastructure. The actual Typst rendering
logic for arrows and calculations will be implemented next.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 08:00:55 -06:00
Thomas Hallock 42c9c9dd7e refactor: simplify borrowed 10s box UI and add place value colors
- Convert "Borrowed 10s Box" from sub-option to peer toggle for clarity
- Remove confusing parent/child relationship with "Borrow Boxes"
- Fix preview not updating when toggling borrowed 10s box (default was false, should be true)
- Add place value color from source digit to borrowed 10s box background
- Fix missing operator field in defaultAdditionConfig and V3→V4 migration
- Simplify description to "Box for adding 10 to borrowing digit"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 08:00:55 -06:00