Commit Graph

77 Commits

Author SHA1 Message Date
Thomas Hallock 6e55d5add7 feat: add visual grab tab to resize handle with rounded corners
Added a 28px × 64px grab tab that extends to the right of the resize
handle divider, providing a larger visual target when the sidebar is
collapsed or near-collapsed.

**Changes:**
- Thin 8px divider remains the draggable area
- Visual grab tab (28px × 64px) extends to right with:
  - Rounded corners on top-right and bottom-right (borderRadius)
  - Vertical knurled texture for grip appearance
  - Drop shadow for depth
  - Positioned absolutely, centered vertically
- Tab is visual decoration only (pointerEvents: none)
- Divider remains fully draggable

**Note:** Tab is not draggable itself (library limitation - child elements
outside parent bounds don't trigger drag). The 8px divider is the
interactive area. Tab provides visual affordance when sidebar is collapsed.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-12 12:30:21 -06:00
Thomas Hallock f409e3c2ed fix: enable virtualization for worksheet preview by limiting SSR to 3 pages
**Root Cause:**
Server was generating ALL pages during SSR and passing them as initialData,
which pre-populated the entire loadedPages Map. This bypassed the
virtualization system because pagesToFetch was always empty.

**Changes:**

1. **page.tsx** - Only generate first 3 pages on server
   - Changed generateWorksheetPreview() to include startPage/endPage params
   - Server now generates min(3, totalPages) instead of all pages
   - Added clear comments explaining SSR vs virtualization split

2. **WorksheetPreview.tsx** - Cleaned up debug logging
   - Removed all console.log statements added during investigation
   - Virtualization logic unchanged (was already correct)

**Result:**
- Initial page load: Fast (only 3 pages)
- Scrolling: Progressive loading with visible network activity
- 100-page worksheet: Loads incrementally as user scrolls
- Memory usage: Only loaded pages in memory, not entire set

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-12 10:41:57 -06:00
Thomas Hallock 5a8779969c feat: add visual warnings to page selector buttons
Implemented proactive duplicate risk warnings directly in the page selector
UI to guide users toward valid configurations before they encounter issues.

**Features:**
- Color-coded page buttons based on duplicate risk
  - Green/brand: Safe (< 50% of space)
  - Yellow: Caution (50-80% of space)
  - Red: Danger (> 80% of space)
- Warning indicator dots on risky page counts
- Radix UI tooltips on hover explaining the risk
- Live problem space calculation based on current config

**Visual Indicators:**
- Border colors change to yellow/red for risky page counts
- Background tints match risk level when selected
- Small dot in top-right corner for at-risk buttons
- Hover shows detailed tooltip with:
  - Total problems requested vs available
  - Duplicate risk level
  - Actionable recommendations

**Implementation:**
- OrientationPanel.tsx: Added problem space validation logic
- Passes digitRange, pAnyStart, operator, mode from form state
- Uses estimateUniqueProblemSpace() for real-time calculation
- Tooltip messages formatted with recommendations
- Skips validation for mastery+mixed mode (consistent with banner)

**Example:**
1-digit 100% regrouping with 15 problems/page:
- Page 1: Green (15 of 45 available)
- Page 2: Yellow warning (30 of 45)
- Page 3: Red danger (45 of 45 - duplicates inevitable)

Tooltip on page 3: "🚫 Too many duplicates: 45 problems requested, only
~45 unique available. Consider: • Reduce to 1 pages • Increase digit range
• Lower regrouping %"

**Next:** Problem space indicator in config panel showing live estimate

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-12 09:36:19 -06:00
Thomas Hallock 11c46c1b44 feat: optimize problem generation and add duplicate warning system
Problem Generation Improvements:
- Implement hybrid approach: generate-all + shuffle for small problem spaces (< 10k), retry-based for large spaces
- Add countRegroupingOperations() for accurate difficulty sorting
- Support progressive difficulty in generate-all mode by sorting problems before sampling
- Fix problem space estimation for 1-digit problems (was 6075, now correctly returns 45 for 100% regrouping)

Duplicate Warning System:
- Add validateProblemSpace() utility to estimate unique problems and warn users
- Create dismissable warning banner with visual styling (yellow bg, 15px rounded corners, drop shadow)
- Position warning banner as floating element alongside page indicator and action button
- Auto-reset dismissed state when worksheet config changes
- Skip validation for complex mastery+mixed mode

Component Refactoring:
- Extract WorksheetPreviewContext for shared state (warnings, theme, form state)
- Extract DuplicateWarningBanner component with context integration
- Move floating elements (warning banner, page indicator) to PreviewCenter for correct positioning
- Fix scroll container structure: preview-center is positioned container, nested div handles scrolling
- Export page data from WorksheetPreview via onPageDataReady callback

Technical Details:
- FloatingPageIndicator changed from position: sticky to position: absolute
- Warning banner positioned at top: 24px, right: 20px to avoid action button overlap
- Remove maxW constraint on scroll container to allow full width flex
- Server logs now show: "0 retries, generate-all method" for small problem spaces

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-12 08:57:00 -06:00
Thomas Hallock e49eadb667 debug: add comprehensive seed tracking logs 2025-11-11 18:42:32 -06:00
Thomas Hallock 7fbc743c4c feat: add skill configuration system with interactive 2D difficulty plot
Implement comprehensive skill customization system allowing teachers to:
- Configure existing default skills with custom difficulty settings
- Create entirely new custom skills from scratch
- Visualize skills in mastery progression context with directional edges
- Interact with difficulty space using 2D plot with hover tooltips

Database Schema:
- custom_skills table: Stores user-created skills
- skill_customizations table: Stores modifications to default skills
- Both tables track regrouping config, display rules, and metadata

API Endpoints:
- POST /api/worksheets/skills/custom - Create custom skill
- GET /api/worksheets/skills/custom - List custom skills
- PUT /api/worksheets/skills/custom/[id] - Update custom skill
- DELETE /api/worksheets/skills/custom/[id] - Delete custom skill
- POST /api/worksheets/skills/[skillId]/customize - Save customization
- GET /api/worksheets/skills/customizations - List customizations

Components:
- DifficultyPlot2D: Interactive 2D visualization of difficulty space
  - Regrouping Intensity (x-axis) × Scaffolding Level (y-axis)
  - Dual mode: Default presets vs Mastery progression skills
  - Directional edges showing skill progression sequence
  - Hover tooltips with skill details
  - Click to select configuration
  - Visual legend explaining elements

- SkillConfigurationModal: Modal for skill configuration
  - Name and description fields
  - Digit range slider
  - 2D difficulty plot integration
  - Shows mastery progression context when editing
  - Real-time configuration summary

- MasteryModePanel Integration:
  - "Configure Skill" button for existing skills
  - "Create Custom Skill" button for new skills
  - Passes mastery progression to modal for context

Visual Design:
- Purple theme (#9333ea) for mastery progression skills
- Green theme (#10b981) for current configuration
- Dashed arrows with triangular arrow heads
- Numbered skill circles with hover tooltips
- Compact legend in top-right corner

Technical Features:
- PlotPoint interface for custom skill plotting
- Conditional snapping to either presets or custom points
- Vector math for arrow head calculations
- Z-ordering: edges before points
- Event propagation control for hover interactions
- Storybook examples for both components

Bug Fixes:
- Fix page indicator stuck on page 1 in WorksheetPreview
  - Changed from threshold-based to most-visible-page tracking
  - Works correctly for both scroll directions

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 15:04:28 -06:00
Thomas Hallock 1c10a82c78 feat: improve shared worksheet viewer UX and multi-page support
Changes to shared worksheet viewer (/worksheets/shared/[id]):
- Move Download, Share, Edit actions from banner to floating action menu
- Main button shows "Edit" in read-only mode (most common action)
- Download and Share available in dropdown menu
- Simplified banner to show only read-only indicator
- Made banner light/dark mode ready with theme-aware colors

Changes to PreviewCenter component:
- Added onShare and onEdit props for read-only mode
- Main button adapts: "Edit" for read-only, "Download" for edit mode
- Dropdown menu adapts based on mode (Download/Share vs Share/Upload)
- Floating action button now always visible

Changes to WorksheetPreview component:
- Fixed virtualization to show all pages when initialData provided
- Shared worksheets now display all pages immediately (no lazy loading)
- Interactive editor still uses virtualization for performance
- Added debug logging for page visibility and theme changes

Bug fixes:
- Fixed page virtualization preventing multiple pages from showing
- Made shouldVirtualize persistent across re-renders
- Added comprehensive logging for debugging theme and page issues

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 13:10:34 -06:00
Thomas Hallock 99ec5eae5e worksheet studio 2025-11-11 11:44:40 -06:00
Thomas Hallock a2ab82620a refactor: eliminate prop drilling with WorksheetConfigContext
Replace prop drilling pattern with React Context for worksheet configuration
state and leverage existing ThemeContext for app-wide theme concerns.

Context Architecture:
- Created WorksheetConfigContext for worksheet-specific state (formState, onChange, operator)
- Use existing global ThemeContext for theme/isDark instead of prop drilling
- Clear separation of concerns: worksheet state vs app-wide theme

Components Refactored:
- DigitRangeSection: removed isDark prop, uses useTheme()
- RegroupingFrequencyPanel: removed ALL props (formState, onChange, isDark), uses both contexts
- SmartModeControls: removed isDark prop, uses useTheme() internally
- DifficultyPresetDropdown: uses both contexts
- MakeEasierHarderButtons: uses useTheme()
- OverallDifficultySlider: uses useTheme()
- ConfigPanel: wraps children with WorksheetConfigProvider
- ManualModeControls: removed isDark from child component calls

Benefits:
- Eliminated 10+ prop declarations and prop-passing statements
- RegroupingFrequencyPanel went from 3 props to 0 props
- Better testability with context providers
- Cleaner component APIs
- Proper separation of worksheet vs app-wide state

Documentation:
- Added PROP_DRILLING_AUDIT.md with comprehensive analysis
- Documents before/after patterns and best practices

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 06:24:24 -06:00
Thomas Hallock e708add9f2 fix: respect user's layout options (problemNumbers/cellBorders) in mastery mode
The problem: When in mastery mode, layout toggles (Problem Numbers and
Cell Borders) appeared to work but had no effect on the worksheet preview.

Root cause: Mastery mode was using hardcoded recommendedScaffolding from
skill definitions, completely overriding user's displayRules choices.

Solution: Merge user's displayRules with skill's recommended scaffolding,
giving user's layout choices (problemNumbers, cellBorders) priority while
still respecting the skill's pedagogical scaffolding recommendations for
other display options.

Changes:
- validation.ts: Override layout options with user choices in mastery mode
- Remove debug logging from OrientationPanel, AdditionWorksheetClient,
  preview API route, and typstGenerator

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 18:53:57 -06:00
Thomas Hallock 0425033080 refactor: move progressive difficulty toggle below operator section
Move the "Progressive difficulty" toggle to appear immediately after
the "Operator" section in the worksheet configuration panel, before
the "Mode Selector". This creates a more logical flow:

1. Student Name
2. Digit Range
3. Operator
4. Progressive Difficulty
5. Mode Selector
6. Mode-specific controls

Previously, Progressive Difficulty appeared after Mode Selector, which
broke the logical grouping of basic settings before mode selection.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 16:10:26 -06:00
Thomas Hallock e156e870df fix: remove redundant 'Teens minus singles' subtraction skill
Remove the sd-sub-borrow skill as it was redundant with the existing
"Two-digit with ones place borrowing" skill which naturally covers
problems like 52-17, 43-18, etc.

The skill was problematic because:
- digitRange: { min: 1, max: 1 } constrained both operands to single digits
- But the description "13-7, 15-8" implied 2-digit minus 1-digit
- This contradiction made it impossible to generate appropriate problems
- Students were seeing either 0% or 100% of the intended pattern

Rather than fix the complex asymmetric digit range logic, we're removing
the skill entirely. The progression now flows:
- sd-sub-no-borrow (single-digit without borrowing)
- td-sub-no-borrow (two-digit without borrowing)
- td-sub-ones-borrow (two-digit with ones place borrowing)

This provides a cleaner, more natural progression.

Changes:
- Remove sd-sub-borrow skill definition from skills.ts
- Remove 'sd-sub-borrow' from SkillId type union
- Update td-sub-no-borrow prerequisites to reference sd-sub-no-borrow
- Remove sd-sub-borrow from skillMigration.ts mapping
- Remove generateTeensMinusSingles() function from problemGenerator.ts
- Revert generateOnesOnlyBorrow() to standard logic

Also includes previous fixes:
- Fix AllSkillsModal tab button types to prevent modal closing
- Add operator-specific display rules for mixed mode
- Add borrowNotation and borrowingHints to displayRules schema

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 15:47:18 -06:00
Thomas Hallock f06a6f2dcd refactor: change operator values from Unicode to alphanumeric strings
**Problem:** Using Unicode characters '+' and '−' (U+2212) as operator flags
causes bugs when developers use the wrong character (ASCII '-' vs Unicode '−').

**Solution:** Changed operator discriminator values to alphanumeric strings:
- Addition: '+' → 'add'
- Subtraction: '−' → 'sub'

**Files changed:**
- types.ts: Updated AdditionProblem and SubtractionProblem operator types
- All operator assignments changed: operator: 'add' / operator: 'sub'
- All operator comparisons changed: === 'add' / === 'sub'

**Benefits:**
- No more Unicode character confusion
- Easier to type and read
- Less error-prone for future developers
- Consistent with WorksheetOperator type ('addition', 'subtraction', 'mixed')

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 14:51:03 -06:00
Thomas Hallock 4ad687df73 fix(worksheets): validation function was converting mastery mode to manual
CRITICAL FIX: The validateWorksheetConfig() function only checked for mode === 'smart',
causing mastery mode configs to fall through to the manual mode path. This meant:
- Frontend sent mode: 'mastery' with displayRules
- Validation function created a manual mode config instead
- displayRules were lost, replaced with boolean flags
- Ten-frames didn't render because flags defaulted to false

Changes:
- validation.ts: Check for both 'smart' OR 'mastery' when using displayRules
- validation.ts: Preserve mode as 'smart' | 'mastery' instead of forcing 'smart'
- validation.ts: Include currentStepId for mastery progression tracking
- types.ts: Import and include AdditionConfigV4Mastery in WorksheetFormState type

This was the third place mastery mode needed to be handled:
1.  config-schemas.ts - Zod schema (added in previous commit)
2.  typstGenerator.ts - Problem enrichment (added in previous commit)
3.  validation.ts - Config validation (this commit)

Tests: All 14 ten-frames tests passing

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 10:25:58 -06:00
Thomas Hallock b36df3a40c fix(worksheets): ten-frames not rendering in mastery mode
Fixed two critical bugs preventing ten-frames from rendering:

1. **Mastery mode not handled** (typstGenerator.ts:61)
   - Code only checked for 'smart' | 'manual' modes
   - Mastery mode fell into manual path, tried to use boolean flags that don't exist
   - Resulted in all display options being `undefined`
   - Fix: Check for both 'smart' OR 'mastery' modes (both use displayRules)

2. **Typst array membership syntax** (already fixed in previous commit)
   - Used `(i in array)` which doesn't work in Typst
   - Changed to `array.contains(i)`

Added comprehensive unit tests (tenFrames.test.ts):
- Problem analysis tests (regrouping detection)
- Display rule evaluation tests
- Full Typst template generation tests
- Mastery mode specific tests
- All 14 tests now passing

Added debug logging to trace display rules resolution:
- displayRules.ts: Shows rule evaluation per problem
- typstGenerator.ts: Shows enriched problems and Typst data
- Helps diagnose future issues

The issue was that mastery mode (which uses displayRules like smart mode)
was being treated as manual mode (which uses boolean flags), resulting in
undefined display options.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 10:06:27 -06:00
Thomas Hallock 2d33f35c4d fix: correct GPT-5 API parameters and surface actual grading errors
Two critical fixes for worksheet grading:

1. **Fix OpenAI Responses API parameters**
   - Move `verbosity` from top-level to `text.verbosity`
   - API was rejecting requests with 400 error
   - Confirmed against GPT-5 Responses API documentation

2. **Surface actual grading errors in UI**
   - Add `error_message` column to worksheet_attempts table
   - Store actual API/grading errors in database
   - Display real error messages instead of generic "too blurry" text
   - Users now see OpenAI API errors, validation failures, etc.

Changes:
- Updated gradeWorksheet.ts API call structure
- Created migration 0020 for error_message column
- Updated processAttempt.ts to save error messages
- Updated API route to return errorMessage field
- Updated results page to display actual errors

Now when grading fails, users see helpful error messages like:
"Unsupported parameter: 'verbosity'..." instead of just "too blurry"

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 06:12:10 -06:00
Thomas Hallock cd75df7221 chore: restore stashed work from previous session
Recover all changes from stash including:
- Linter/formatter updates across codebase
- Settings permission updates for git checkout

This commit captures the complete state of work that was
stashed during the previous session's git operations.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 14:59:40 -06:00
Thomas Hallock 5a8fc5735d chore: update Claude settings 2025-11-08 14:58:01 -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 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 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 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 3541b792d5 refactor(worksheets): simplify scaffolding summary with grouped frequency
Changed from per-item mode badges to a cleaner grouped format:

Before:
  carry boxes [always] · answer boxes [when regrouping] · ten-frames [2+ regroups]

After:
  Always: carry boxes, answer boxes  •  When needed: ten-frames

This reduces cognitive load by:
- Grouping scaffolding aids by frequency instead of individual labels
- Using simple "Always" vs "When needed" instead of detailed conditions
- Eliminating repetitive badge styling that added visual noise
- Making the summary more scannable at a glance

Users get the key information (what's enabled, when it shows) without
needing to parse multiple conditional badges per item.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:09:35 -06:00
Thomas Hallock eaeeae4ce8 feat(worksheets): add visual mode badges to scaffolding summary
Display conditional scaffolding modes with color-coded badges:
- Green 'always' - unconditionally shown
- Yellow 'when regrouping' - shown for problems with any regrouping
- Orange '2+ regroups' - shown for problems with multiple regroups
- Blue '3+ digits' - shown for problems with 3+ digit operands

Example output:
  carry boxes [always] · answer boxes [when regrouping] · ten-frames [2+ regroups]

This makes it immediately clear to users when each scaffolding aid
will appear in the generated worksheets, replacing the previous
text-only list that didn't communicate the conditional nature.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:09:35 -06:00
Thomas Hallock 2797038502 fix(worksheets): correct scaffolding summary to include all conditional modes
Bug: getScaffoldingSummary() only checked for 'always' or 'whenRegrouping',
missing 'whenMultipleRegroups' and 'when3PlusDigits' modes.

This caused configs with tenFrames: 'whenMultipleRegroups' to show
'no scaffolding' in the summary, even though ten-frames would appear
on problems with multiple regroups.

Fix: Changed from whitelist (=== 'always' || === 'whenRegrouping')
to blacklist (!== 'never') approach. Now correctly identifies any mode
that enables scaffolding, including all conditional modes.

Added comprehensive console logging to debug the issue:
- ConfigPanel.tsx: getScaffoldingSummary() logs each rule evaluation
- typstGenerator.ts: logs config mode and first problem display options
- displayRules.ts: logs rule resolution for each problem

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 22:09:35 -06:00
Thomas Hallock 852504a4fd feat(worksheets): improve preset dropdown with descriptions and remove duplicate buttons
- Show preset description in collapsed dropdown state
- Show 'Settings modified from preset' message for custom configs
- Remove redundant preset button grid below 2D plot
- Cleaner, more compact UI with all preset selection in one place
- Maintains full two-way binding between dropdown and sliders
2025-11-07 22:09:35 -06:00
Thomas Hallock 2e0f99f98a refactor(worksheets): extract utility functions
- dateFormatting.ts: getDefaultDate() for consistent date formatting
- layoutCalculations.ts: getDefaultColsForProblemsPerPage() and calculateDerivedState()
- Pure functions, easy to test
- Removes 32 lines from main component
2025-11-07 22:09:35 -06:00
Thomas Hallock 369b7f263d docs(worksheets): add two-mode system planning docs and update API route
TWO_MODE_SYSTEM_PLAN.md:
- Initial planning document for Smart/Manual mode system
- Research-backed difficulty progression rationale
- Display rules architecture

TWO_MODE_IMPLEMENTATION_PLAN.md:
- Detailed implementation plan with phase breakdown
- Migration strategy, validation approach
- Testing checklist

difficultyProfiles.ts:
- Add mode-aware comments for Smart mode integration

API route and settings:
- Update settings persistence for V3 schema
- Claude Code settings updates
2025-11-07 22:09:35 -06:00
Thomas Hallock 7c33d0246f fix: prevent undefined displayRules error in worksheet generator
Fixes production error "Cannot read properties of undefined (reading 'carryBoxes')"
that occurred when users tried to adjust difficulty settings.

Root cause: displayRules was undefined for new users or users with old V1 config
in database. Difficulty adjustment buttons accessed displayRules.carryBoxes without
checking if displayRules existed first.

Changes:
- AdditionWorksheetClient: Initialize displayRules with defaults when missing
- ConfigPanel: Use null-coalescing operators instead of non-null assertions
- ConfigPanel: Add error logging when required fields are missing
- NEW: WorksheetErrorBoundary component to catch all errors in worksheet page
- page.tsx: Wrap client component with error boundary

This ensures users see helpful error messages instead of blank pages,
and never need to open the browser console to understand what went wrong.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 13:01:54 -06:00
Thomas Hallock 59d594c939 chore: run biome formatting
Apply automated formatting fixes:
- Add trailing commas for consistency
- Break long lines for readability
- Normalize indentation
- Remove extraneous blank lines

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-05 08:43:52 -06:00
Thomas Hallock 5d97673406 fix: remove wobble physics and enhance wood grain visibility
**Changes:**
- Removed wobble physics feature (was janky and distracting)
- Increased wood grain opacity from 0.15 → 0.4 (realistic) and 0.45 (delightful)
- Enhanced wood grain pattern with bolder strokes and more visible knots
- Removed getWobbleRotation utility function
- Simplified Abacus3DPhysics interface to only hoverParallax
- Updated all stories to remove wobble references
- Removed velocity tracking code from Bead component

Wood grain is now much more visible on frame elements without
affecting bead spacing or layout.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 15:41:49 -06:00
Thomas Hallock ed9a050d64 fix: resolve z-index layering and hero abacus visibility issues
Fix two critical issues with the trophy abacus system:

1. Hero abacus appearing on all pages:
   - Root cause: HomeHeroProvider now wraps all pages globally
   - Solution: Use pathname check to detect actual home page routes
   - Only show hero mode on: /, /en, /de, /ja, /hi, /es, /la

2. Z-index conflicts causing layering issues:
   - AppNavBar had hardcoded z-index: 1000 (DROPDOWN layer)
   - Should use Z_INDEX.NAV_BAR (100) for proper layering
   - Tooltip had z-index: 50, should use Z_INDEX.TOOLTIP (1000)

This ensures:
- Hero abacus only appears on home page, not all pages
- Trophy abacus (z-index 30001) appears above ALL content
- Nav bar and tooltips use correct z-index constants
- No stacking context conflicts

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 13:24:15 -06:00
Thomas Hallock 423274657c fix: correct hero abacus scroll direction to flow with page content
The hero abacus was scrolling in the opposite direction of page content due to incorrect math. Fixed by subtracting scroll position instead of adding it.

Change: top: calc(50vh - ${scrollY}px) instead of calc(50vh + ${scrollY}px)

Now the abacus properly scrolls up with the page content when scrolling down.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 13:24:15 -06:00
Thomas Hallock b67cf610c5 fix: various game improvements and UI enhancements
Collection of improvements across multiple games and components:

- Complement Race: Improve sound effects timing and reliability
- Card Sorting: Enhance drag-and-drop physics and visual feedback
- Memory Quiz: Fix input phase keyboard navigation
- Rithmomachia: Update playing guide modal content and layout
- PageWithNav: Add viewport context integration
- ArcadeSession: Improve session state management and cleanup
- Global CSS: Add utility classes for 3D transforms

Documentation:
- Add Google Classroom setup guide
- Update Claude Code settings

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 10:53:54 -06:00
Thomas Hallock fb629c44ea refactor: reorganize Harmony and Victory guide sections
Eliminated duplication between Harmony and Victory tabs:

**Harmony Tab** (focus: what ARE harmonies and how to FORM them):
- Renamed title to "Mathematical Progressions" (clearer focus)
- Updated intro to focus on patterns, not winning
- Removed "Important Rules" section (moved to Victory)
- Kept: 3 harmony types, formation strategies, quick reference

**Victory Tab** (focus: how to WIN):
- Expanded harmony victory section with placement requirements:
  - Must be in enemy territory
  - Must be in straight line
  - Must be adjacent/touching
  - Must form progression
  - Must survive one turn
- Added reference to Harmony tab for progression details
- Kept: Exhaustion victory, strategy tips

Benefits:
- Clear separation of concerns
- No duplication
- Better learning flow
- Matches SPEC.md simplified rules

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-02 19:38:13 -06:00
Thomas Hallock b5a96eaeb1 fix: board rotation now properly fills height in portrait mode
Fixed board rotation issues when guide is docked:
- Board now prioritizes HEIGHT when in portrait orientation
- Removed CSS constraints (maxWidth, maxHeight, aspectRatio) that were
  interfering with explicit dimensions during rotation
- Board properly fills container whether guide is docked or not
- Smooth transition between portrait and landscape orientations

Technical changes:
- Set maxWidth/maxHeight to 'none' when svgDimensions are explicit
- Set aspectRatio to 'auto' when rotating to prevent override
- Cleaned up debug logging

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-02 19:06:41 -06:00
Thomas Hallock 4ce561e785 debug: add console logging for hover error tooltip and guide dragging
Added targeted console logging to help debug two issues:
1. Capture error tooltip on hover - logs mouse events, piece detection,
   path validation, and relation checking
2. Guide dragging from docked state - logs drag events, undocking logic,
   and position calculations

All logs use string concatenation and are prefixed with [HOVER_ERROR]
or [GUIDE_DRAG] for easy filtering. Removed unrelated debug logging.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-02 13:59:06 -06:00
Thomas Hallock 61f899ce99 chore: update auto-approve permissions for bash commands
Add auto-approve for additional bash commands:
- Git operations (rev-parse)
- File operations (head, tail, jq)
- Pnpm package management
- Web fetch for hub.docker.com

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-01 14:47:25 -05:00
Thomas Hallock 3121d8240a feat(rithmomachia): Add interactive playing guide modal
Add comprehensive draggable playing guide modal with quick navigation:
- Draggable modal on desktop, fixed on mobile
- 5 quick-access sections: Overview, Pieces, Capture, Harmony, Victory
- Integrated PieceRenderer SVGs for visual piece examples
- Responsive layout for desktop and mobile
- Modal persists during gameplay
- "How to Play" button on setup page with updated description
- "Guide" button in gameplay controls
- Complete guide content from PLAYING_GUIDE.md

Features:
- Desktop: draggable modal that can be positioned anywhere
- Mobile: full-screen responsive modal
- Quick navigation tabs for easy reference
- Visual piece examples with movement descriptions
- Mathematical capture relations explained
- Harmony progression examples with formulas
- Strategy tips and victory conditions

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-31 19:59:09 -05:00
Thomas Hallock 709322373a fix(rithmomachia): adjust roster notice position to not overlap nav
- Move notice from top: 80px to top: 180px
- Use Z_INDEX.GAME.OVERLAY instead of hardcoded value
- Ensures game nav and player list remain visible

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 04:39:00 -05:00
Thomas Hallock bd014bec4f fix(card-sorting): prevent ghost movements with proper optimistic updates
Fixes ghost movements when dragging cards by properly tracking which
position updates originated from this browser window/tab.

Previously used a timing-based approach (debounce) which was brittle
and didn't work reliably on slow connections.

New approach:
- Generate unique windowId for each browser tab
- Include windowId in all position updates sent to server
- Skip server position updates that contain our own windowId
- This prevents replaying our own movements when they echo back

The user should never see their own movements repeated since they
already have those positions locally applied.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-25 07:15:33 -05:00
Thomas Hallock 646a4228d0 fix(qr-button): improve layout and z-index
- Stack room code and share link vertically on left
- Place square QR button on right, spanning both rows
- Show mini QR code (40px) in button instead of emoji
- Fix popover z-index to appear above dropdown menu (z: 10000)
- Reduce button padding for more compact appearance

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-23 10:35:22 -05:00
Thomas Hallock a1a135a858 feat: add vibrant gradients and equal heights to game cards
Updated the game theme system and game cards to have vibrant, eye-catching
gradients and consistent heights:

Theme System Changes:
- Updated all game themes from pastel to vibrant gradients
- Blue: Vibrant cyan (#4facfe to #00f2fe)
- Purple: Vibrant purple (#667eea to #764ba2)
- Pink: Vibrant pink (#f093fb to #f5576c)
- Green: Vibrant green/teal (#43e97b to #38f9d7)
- Plus updated indigo, teal, orange, yellow, red, gray themes

Game Manifest Updates:
- Memory Lightning: now uses purple theme
- Matching Pairs: now uses pink theme
- Complement Race: continues using blue (cyan) theme
- Card Sorting: now uses green theme

Homepage Game Cards:
- Added height: '100%' and flexbox to make all cards equal height
- Cards now stretch uniformly regardless of content length
- Maintains responsive hover effects and text readability overlays

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 17:13:09 -05:00
Thomas Hallock c883d9e4c1 fix(tutorial): resolve React hydration error in TutorialPlayer
Change <p> tag to <div> tag to fix HTML nesting violation. The
<p> tag was containing <DecompositionWithReasons> which renders
a <div>, causing a hydration error. In HTML, <p> cannot contain
block-level elements like <div>.

Fixed: apps/web/src/components/tutorial/TutorialPlayer.tsx:1386

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-19 12:41:33 -05:00
Thomas Hallock ebe123ed7e fix: replace native alerts with inline confirmations in ModerationPanel
Removed native browser confirm() dialogs and replaced with React state-based inline confirmations:
- Removed confirm() from handleKick (kicks happen immediately)
- Removed confirm() from handleTransferOwnership
- Added confirmingTransferOwnership state variable
- Added inline confirmation UI with Cancel/Confirm buttons
- Follows pattern documented in UI_STYLE_GUIDE.md

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-19 12:07:18 -05:00
Thomas Hallock feecda78d0 chore: update Claude Code permissions
Auto-updated permissions during session.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-18 19:49:17 -05:00
Thomas Hallock 0209975af6 refactor(arcade): standardize game card themes with preset system
Create a centralized theme system to prevent inconsistent game card
styling. All games now use standard color presets instead of manually
specifying gradients.

## Changes

**New Theme System:**
- Created `/src/lib/arcade/game-themes.ts` with 10 standard themes
- All themes use Tailwind 100-200 colors for consistent pastel appearance
- Exported `getGameTheme()` helper and `GAME_THEMES` constants via SDK
- Added comprehensive documentation in `.claude/GAME_THEMES.md`

**Migrated All Games:**
- card-sorting: Uses `getGameTheme('teal')`
- memory-quiz: Uses `getGameTheme('blue')`
- matching: Uses `getGameTheme('purple')`
- complement-race: Uses `getGameTheme('blue')`

**Benefits:**
-  Prevents future styling inconsistencies
-  One-line theme setup instead of three properties
-  TypeScript autocomplete for available themes
-  Centralized maintenance - update all games by changing theme definition
-  Clear documentation prevents mistakes

**Before:**
```typescript
color: 'teal',
gradient: 'linear-gradient(135deg, #99f6e4, #5eead4)',  // Manual, error-prone
borderColor: 'teal.200',
```

**After:**
```typescript
...getGameTheme('teal')  // Simple, consistent, discoverable
```

This fixes the root cause where card-sorting needed manual gradient
adjustments - now all games automatically get professional styling.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-18 19:00:38 -05:00
Thomas Hallock ee6c4f2f4f feat(home): redesign home page to showcase complete platform
Replace outdated "flashcard generator" landing page with comprehensive
platform showcase highlighting all three pillars: arcade games,
interactive learning, and flashcard creation.

**New Home Page Structure:**
- Compact hero with 3 CTAs: Play Games, Learn, Create
- 4 arcade game cards with player counts and mode tags
- Two-column feature sections for Learning & Flashcards
- Multiplayer features grid (4 cards)
- Stats banner: 4 games, 8 max players, 3 learning modes, 4+ formats

**Visual Design:**
- Smaller, denser components to fit more content
- Information-rich showcase vs marketing fluff
- Purple gradient hero matching guide branding
- Responsive grid layouts for all screen sizes

**Result:**
Home page now accurately represents the full platform:
multiplayer arcade games + interactive tutorials + flashcard tools.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-18 17:33:01 -05:00
Thomas Hallock 7f6fea91f6 feat(card-sorting): implement Provider with arcade session integration
Add complete Provider implementation for Card Sorting Challenge game.

Features:
- Full useArcadeSession integration with optimistic updates
- Config persistence to database (gameConfig.card-sorting)
- Single-player pattern (local player selection)
- Pause/resume support with config change detection
- Action creators for all 8 move types:
  * startGame() - generates random cards
  * placeCard(cardId, position) - place card in slot
  * removeCard(position) - return card to available
  * checkSolution() - validate answer & calculate score
  * revealNumbers() - show numeric values
  * goToSetup() - pause/return to setup
  * resumeGame() - restore paused game
  * setConfig() - update game settings
- Computed values: canCheckSolution, placedCount, elapsedTime
- Local UI state: selectedCardId (not synced)
- useCardSorting() hook for component access

Next: UI components (Setup, Playing, Results)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-18 14:11:52 -05:00
Thomas Hallock 22426f677f refactor: remove dead Python bridge and unused packages
Removed abandoned SVG generation code that was never used in production:

**Deleted Files:**
- packages/core/src/bridge.py (302 lines) - Python-shell bridge for SVG generation
- packages/core/client/node/src/soroban-generator-bridge.ts - TypeScript wrapper
- packages/core/client/typescript/ - Entire unused @soroban/client package
- packages/core/client/browser/ - Empty package

**Dependencies Removed:**
- python-shell - Only used by abandoned bridge code
- @types/minimatch - Only needed by removed TypeScript packages
- @soroban/client from apps/web

**Code Cleanup:**
- Simplified packages/core/client/node/src/index.ts exports
- Removed SorobanGeneratorBridge, BridgeFlashcardConfig, BridgeFlashcardResult exports

**Impact:**
- ~800 lines of dead TypeScript code removed
- 302 lines of unused Python code removed
- 2 npm dependencies removed
- Build verified successful - no functionality affected

**What Remains Active:**
- generate.py - PDF generation via Typst CLI (actively used by /api/generate)
- soroban-generator.ts - CLI wrapper for PDF generation
- api.py - Optional FastAPI server
- generate_examples.py - Documentation image generator
- Web app uses @soroban/abacus-react for all SVG rendering

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-18 09:11:59 -05:00