Commit Graph

1435 Commits

Author SHA1 Message Date
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
Thomas Hallock 41b5c057ed feat: refactor borrow scaffolding into unified UI with column alignment
Consolidated subtraction borrow scaffolding options:
- Removed standalone "Borrow Notation Boxes" toggle
- Made it a sub-option under "Borrow Boxes" (like Ten-Frames)
- Created reusable SubOption component for nested toggles
- Renamed to "Hide Borrowed 10s Box" (inverted logic, default shown)

UI improvements:
- Factored out SubOption component with smaller toggle switches
- Reorganized grid: Borrow Boxes and Ten-Frames on same row
- Both use consistent parent/child toggle pattern
- Removed auto-disable logic (Check All doesn't touch sub-options)

Alignment fixes:
- Removed dashed source boxes above digits (use diagonal borrow boxes instead)
- Added invisible box spacing to maintain digit alignment in columns with borrowing
- Only columns that need borrowing get box spacing
- All digits in affected columns align vertically (minuend and subtrahend)

Defaults:
- Borrow boxes: ON (shows diagonal split boxes)
- Borrowed 10s box: shown by default (unchecked = shown)
- Default changed from false to true for showBorrowNotation

🤖 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 17307f7e82 fix: make borrow notation destination boxes full height
- Updated destination borrow boxes to 95% cell height (was 50%)
- Increased width to 45% (was 40%) for better visibility
- Added showBorrowNotation to DisplayOptionsPreview component
- Fixed example route to pass showBorrowNotation parameter
- Boxes now extend nearly full height of digit cell for kids to write big

🤖 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 a01fa818b4 fix(worksheets): Make destination borrow box more visible
Increase size and border thickness of destination digit scratch box:
- Width: 35% → 40% of cell size
- Height: 35% → 50% of cell size
- Border: 0.5pt → 1pt thickness
- Add proper alignment wrapper around stack

Makes the box easier to see and write in.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 23:07:08 -06:00
Thomas Hallock e9d52bab49 fix(worksheets): Set showBorrowNotation to false for smart mode
Smart mode doesn't have the showBorrowNotation field in config, so
enrichedProblems had undefined for this field. This caused Typst
compilation errors.

Fix: Explicitly set showBorrowNotation to false for smart mode problems.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 23:00:52 -06:00
Thomas Hallock ff161d4e30 feat(worksheets): Add borrow notation scaffolding for subtraction
Implements empty scratch boxes to guide students through borrowing work
without doing the arithmetic for them.

Scaffolding design:
1. **Source digit box** (above) - Student crosses out original and writes
   reduced value (e.g., cross out 5, write 4)
2. **Destination digit box** (left side) - Student writes modified value
   after adding 10 (e.g., write "12" next to 2)

Both boxes:
- Dotted borders to indicate workspace
- ~35-50% size of main digit cells
- Positioned close to the digits they modify
- Only appear where borrowing is needed

Implementation:
- Add `showBorrowNotation` boolean to V4 manual schema
- Update Typst rendering with conditional notation rows
- Add UI toggle (only shows for subtraction/mixed modes)
- Include in validation and auto-save persistence
- Update typstGenerator and example routes

Pedagogical approach: Shows WHERE and provides space for WHAT,
but student must determine and write the actual values.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:58:38 -06:00
Thomas Hallock 97ddc7ee67 fix(worksheets): Add operator to preview query key and update UI labels
Two fixes:

1. **Preview cache invalidation**: Add formState.operator to WorksheetPreview
   query key so preview refreshes when switching between addition/subtraction/mixed

2. **Dynamic UI labels**: Update "Carry Boxes" label to show:
   - "Carry Boxes" for addition mode
   - "Borrow Boxes" for subtraction mode
   - "Carry/Borrow Boxes" for mixed mode

   Description text also updates to match operator type.

Scaffolding for borrowing:
- Borrow boxes (diagonal split boxes showing source → destination)
- Displayed FROM higher place TO lower place (opposite of carries)
- Same underlying field (showCarryBoxes) controls both

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:34:27 -06:00
Thomas Hallock d93dfac461 feat(worksheets): Phase 10 - Add operator validation
Adds validation for operator field in worksheet config:
- Validate operator is one of: addition, subtraction, or mixed
- Add clarifying comment that digit range applies to both operations
- All other validation rules apply uniformly to both operators

Completes the 10-phase implementation plan for subtraction support.
The worksheet creator now fully supports:
- Addition only
- Subtraction only
- Mixed mode (50/50 addition and subtraction)

All phases complete:
1.  Operator selection UI
2.  Subtraction problem generation
3.  Problem analysis for smart mode
4.  Typst rendering with borrow boxes
5.  Unified typstGenerator dispatch
6.  Display rules for both operators
7.  Auto-save persistence
8.  Preview/example routes
9.  DisplayOptionsPreview component
10.  Validation

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:32:14 -06:00
Thomas Hallock d5bbd783b3 feat(worksheets): Phase 9 - Update DisplayOptionsPreview for operator
Updates DisplayOptionsPreview component to support operator selection:
- Add operator field to fetchExample options
- Build request options dynamically based on operator type
- Use addend1/addend2 for addition, minuend/subtrahend for subtraction
- Update MathSentence to show correct operator symbol (+ or −)
- Update input labels based on operator (addend vs minuend/subtrahend)
- Include operator in debounce dependencies

The preview now correctly updates when switching between addition/subtraction/mixed modes.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:31:34 -06:00
Thomas Hallock 010606848d feat(worksheets): Phase 8 - Update preview and example routes for operator
Updates worksheet generation routes to support operator selection:

Example route (example/route.ts):
- Add operator, minuend, subtrahend fields to ExampleRequest
- Split generateExampleTypst into addition/subtraction branches
- Use generateSubtractionProblems for subtraction examples
- Render with subtraction-problem-stack function

Preview generation (generatePreview.ts):
- Import subtraction and mixed problem generators
- Dispatch to correct generator based on operator field
- Support addition, subtraction, and mixed modes

Both routes now correctly generate previews for all three operator modes.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:30:15 -06:00
Thomas Hallock 01d095942d feat(worksheets): Phase 7 - Add operator to auto-save persistence
Updates useWorksheetAutoSave hook to persist operator field:
- Add operator to destructured fields
- Include operator in saved config object

This ensures the user's operator selection (addition/subtraction/mixed)
is preserved across sessions.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:30:15 -06:00
Thomas Hallock b191bb9a82 feat(worksheets): Phase 5 - Update typstGenerator for operator support
Updates typstGenerator.ts to handle both addition and subtraction:
- Import WorksheetProblem union type instead of just AdditionProblem
- Import subtraction rendering and analysis functions
- Update calculateMaxDigits to handle both operators
- Update problem enrichment to analyze addition vs subtraction
- Generate Typst problem data with operator discriminator
- Dispatch to correct rendering function based on operator
- Update displayRules to handle both ProblemMeta and SubtractionProblemMeta

Also updates:
- problemGenerator.ts: Add operator field to AdditionProblem
- displayRules.ts: Support AnyProblemMeta union type
- validation.ts: Add operator to shared config fields

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:30:15 -06:00
Thomas Hallock a7b48a2879 feat(worksheets): add subtraction problem analysis and implementation plan
Phase 3: Problem Analysis
- Added SubtractionProblemMeta interface with borrow detection
- Implemented analyzeSubtractionProblem() function
- Tracks borrowing through all place values (1-6 digits)
- Returns borrow count and specific places requiring borrowing

Documentation:
- Added comprehensive SUBTRACTION_AND_OPERATOR_PLAN.md
- Documents all 10 implementation phases
- Includes Typst rendering details, UI updates, validation
- Provides testing strategy and migration path

Still TODO (Phases 4-10):
- Phase 4: Typst rendering (generateSubtractionProblemStackFunction)
- Phase 5: Update typstGenerator for unified rendering
- Phase 6: Update display rules for subtraction
- Phase 7: Auto-save operator persistence
- Phase 8: Preview/example API routes
- Phase 9: DisplayOptionsPreview component
- Phase 10: Validation

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:20:51 -06:00
Thomas Hallock ab87c6ebe7 feat(worksheets): add operator selection and subtraction problem generation
Phase 1: Operator Selection UI
- Added WorksheetOperator type ('addition' | 'subtraction' | 'mixed')
- Added operator field to V4 config schema with default 'addition'
- Added operator selector UI in ConfigPanel with 3 buttons
- Unified problem types (AdditionProblem, SubtractionProblem, WorksheetProblem)

Phase 2: Subtraction Problem Generation
- Implemented generateNonBorrow() - no borrowing in any place
- Implemented generateOnesOnlyBorrow() - borrow in ones place only
- Implemented generateBothBorrow() - multiple borrows
- Implemented generateSubtractionProblems() - main generation with digit ranges
- Implemented generateMixedProblems() - 50/50 addition/subtraction mix
- All functions ensure minuend ≥ subtrahend (no negative results)
- Borrow detection works across all place values (1-5 digits)

Next phases will add:
- Subtraction problem analysis
- Typst rendering for subtraction (borrow boxes, etc.)
- Display rules and smart mode support
- Auto-save persistence
- Preview/example routes

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:19:45 -06:00
Thomas Hallock 258b9ac1b4 fix(worksheets): update display options preview to use new problem-stack signature
Problem: Display options preview failed with "unexpected argument" error.

Root cause: Example route was calling problem-stack with old signature
that had individual digit parameters (aT, aO, bT, bO), but the function
was refactored to extract digits internally from full numbers.

Solution: Updated to new signature:
- Old: problem-stack(a, b, aT, aO, bT, bO, index, ...)
- New: problem-stack(a, b, index, show-carries, show-answers, ...)

Removed manual digit extraction and let the function handle it internally.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:09:36 -06:00
Thomas Hallock c87499535a fix(worksheets): persist digitRange and manualPreset in auto-save
Added missing V4 fields to auto-save hook:
- digitRange (min/max digit configuration)
- manualPreset (manual mode preset selection)

These fields were already in the form state but weren't being saved
to the server, causing settings to not persist across sessions.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:09:36 -06:00
Thomas Hallock 130bbd49dd fix(worksheets): dynamically size grid based on actual problem digits
Problem: All problems rendered with max-digits columns (e.g., 5 columns
for 2-digit problems), showing scaffolding for unused place values.

Root cause: Grid column count was fixed at page-level max-digits, and
all rendering loops used max-digits instead of per-problem actual-digits.

Solution:
- Calculate actual-digits per problem (max of addends + sum, accounting
  for overflow like 99+1=100)
- Extract max-digits+1 positions to capture sum overflow
- Generate column-list dynamically in Typst based on actual-digits
- Update all loops to use actual-digits instead of max-digits
- Hide leading zeros by checking i <= highest position

Now a 2-digit problem gets a 3-column grid (allowing sum overflow),
and a 5-digit problem gets a 6-column grid. Each problem renders
exactly the scaffolding it needs.

Includes:
- Leading zero detection (a-highest, b-highest, sum-highest)
- Dynamic column list generation in Typst
- Ten-frames support for all place values (removed digit restrictions)
- Proper overflow handling for sums

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:09:36 -06:00
Thomas Hallock c0298cf65d feat(worksheets): replace digit selector with Radix double-thumbed slider
Replaced button groups with @radix-ui/react-slider for min/max digit
range selection. Features:

- Double-thumbed range slider (1-5 digits)
- Tick marks above slider showing digit values
- Visual feedback (grab cursor, scale on hover, focus rings)
- More intuitive UX for selecting digit ranges

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:09:36 -06:00
Thomas Hallock 65e272c570 feat(worksheets): implement unique place value colors for 1-6 digit problems
Added 6 unique pastel colors (ones through hundred-thousands) with
dynamic color lookup using array indexing instead of hardcoded ternaries.

Colors:
- Ones: Light blue (rgb(227, 242, 253))
- Tens: Light green (rgb(232, 245, 233))
- Hundreds: Light yellow (rgb(255, 249, 196))
- Thousands: Light pink/rose (rgb(255, 228, 225))
- Ten-thousands: Light purple/lavender (rgb(243, 229, 245))
- Hundred-thousands: Light peach/orange (rgb(255, 239, 213))

All place value rendering (carry boxes, addends, answer boxes, ten-frames)
now uses place-colors.at(i) for dynamic lookup.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:09:36 -06:00
Thomas Hallock d9b54a736c fix(worksheets): add V4 fields to preview query key for cache invalidation
Problem: Preview wasn't regenerating when digitRange changed because
the query key was missing V4 fields (digitRange, mode, displayRules,
difficultyProfile, manualPreset).

Solution: Added all V4 fields to the queryKey array so TanStack Query
properly invalidates and refetches when these settings change.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:09:36 -06:00
Thomas Hallock b92b702223 feat(worksheets): add interactive 2D difficulty map with hover preview
Major improvements to the difficulty space visualization:

**2D Map Enhancements:**
- Fixed Y-axis click handling (scaffolding index was inverted)
- Polished for production: blue theme, responsive sizing (up to 500px)
- Collapsed by default with disclosure control
- Better typography, shadows, and spacing

**Hover Preview System:**
- Orange marker shows exact click target on map
- Dashed line connects current position to hover target
- Preset snapping within 1.0 unit threshold
- Real-time difficulty description updates with "(hover preview)" label
- Orange color theme ties hover state together visually

**UI Polish:**
- Removed obsolete "You're here (Custom)" status text
- Reduced Overall Difficulty slider margins for better spacing
- Cleaner, more professional appearance throughout

The map now provides complete feedback before clicking: visual marker
on map + detailed description preview + preset snapping.

🎨 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:09:36 -06:00
Thomas Hallock 0bc8272830 fix(worksheets): show ten-frames in smart mode when rule is 'always'
Fixed bug where ten-frames wouldn't show in smart mode even when
displayRules.tenFrames was set to 'always' (e.g., beginner preset).

Now sets show-ten-frames-for-all Typst variable to true when:
- Manual mode: config.showTenFramesForAll is true
- Smart mode: config.displayRules.tenFrames === 'always'

This ensures beginner mode shows ten-frames on all problems as intended.
2025-11-07 22:09:36 -06:00
Thomas Hallock d99151239d fix(worksheets): use imperative voice for difficulty adjustment button labels
Changed button labels from past tense to imperative:
- 'Increased regrouping' → 'Increase regrouping'
- 'Reduced regrouping' → 'Reduce regrouping'
- 'Added scaffolding' → 'Add scaffolding'

Buttons now describe what WILL happen when clicked, not what was done.
2025-11-07 22:09:36 -06:00
Thomas Hallock 54abd5de09 feat(worksheets): make progressive difficulty available in both Smart and Manual modes
Moved the progressive difficulty checkbox outside mode-specific sections
so it's available for both Smart and Manual modes.

Previously: Only available in Manual mode
Now: Available in both modes as a shared setting

The checkbox is now in its own card section below mode-specific controls,
making it clear that it applies regardless of which mode is selected.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:09:36 -06:00
Thomas Hallock d52b2aa4aa revert: remove all color-coding attempts for difficulty presets
Reverting commits:
- 0a5812c9 fix(worksheets): use white text on colored backgrounds
- 5d8ac63c feat(worksheets): use more vibrant and distinct difficulty colors
- e641b5e3 feat(worksheets): implement true RGB color interpolation
- a7cef56f fix(worksheets): increase color visibility for difficulty presets
- a09a1cbb feat(worksheets): add color-coding to difficulty presets

Returning to simple, uncolored preset buttons.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:09:36 -06:00
Thomas Hallock 2b7b8ecc87 fix(worksheets): use white text on colored backgrounds for readability
Changed from light backgrounds with dark text to saturated backgrounds
with white text. This provides much better contrast and visibility.

Before: Light .100 backgrounds with dark .700-.800 text (invisible!)
After: Saturated .500-.600 backgrounds with white text (high contrast)

All difficulty levels now use white text on vibrant colored backgrounds:
- Emerald.500 + white text
- Cyan.500 + white text
- Purple.500 + white text
- Amber.500 + white text
- Red.600 + white text

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:09:36 -06:00
Thomas Hallock 984b75cb94 feat(worksheets): use more vibrant and distinct difficulty colors
New color progression:
- Beginner: Emerald (fresh, encouraging green)
- Early Learner: Cyan (calm, learning blue)
- Intermediate: Purple (transitional, neutral)
- Advanced: Amber (warming up, getting challenging)
- Expert: Crimson (intense red)

Changes from previous:
- More saturated and visually distinct colors
- Purple breaks up the green→yellow→red monotony
- Better visual separation between adjacent levels
- All colors maintain high contrast text (.700-.800)
- Backgrounds remain light (.100) for readability

The new palette creates a more interesting visual journey
through the difficulty progression and makes it easier to
distinguish levels at a glance.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:09:36 -06:00
Thomas Hallock 952cffa2d1 feat(worksheets): implement true RGB color interpolation for custom difficulty
Previously was using binary selection (pick closer preset's color).
Now performs smooth linear RGB interpolation based on pythagorean
distance in 2D difficulty space.

Implementation:
- Added DIFFICULTY_RGB with actual RGB values for each preset
- Created interpolateRGB() to blend colors channel-by-channel
- getInterpolatedColor() now returns rgb() strings instead of tokens
- Panda CSS accepts both tokens (presets) and RGB strings (custom)

When moving slider between presets, the button color now smoothly
transitions through the color spectrum (green → blue → yellow →
orange → red) based on exact position in difficulty space.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:09:36 -06:00
Thomas Hallock a7412adbee fix(worksheets): increase color visibility for difficulty presets
Changed from .50 backgrounds to .100 for better visibility
Changed early learner from cyan to blue for better distinction
Changed borders from .400 to .500 for more prominent accents
Changed text from .700 to .800 for better contrast

The cyan.50 background was nearly invisible against white.
New colors are still subtle but clearly visible.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:09:36 -06:00
Thomas Hallock b1201b83c0 feat(worksheets): add color-coding to difficulty presets with interpolation
Added subtle color progression from green (easy) to red (hard):
- Beginner: Green
- Early Learner: Cyan
- Intermediate: Yellow
- Advanced: Orange
- Expert: Red

Features:
- Dropdown button background/border uses preset color
- Dropdown menu items have colored left border accent
- Custom configurations interpolate color based on pythagorean distance
  between two nearest presets in 2D difficulty space
- Hover states use subtle opacity changes to avoid visual clash

Colors are intentionally subtle (using .50 backgrounds, .400 borders,
.700 text) to avoid being distracting while still providing visual
feedback about difficulty level.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:09:36 -06:00