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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
- 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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
- 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
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.
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
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
- 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
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
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.
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>
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>
- 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>