Commit Graph

1929 Commits

Author SHA1 Message Date
Thomas Hallock
8a9afa86bc fix(practice): disable auto-scroll and add modern PWA meta tag
- Add scroll: false to all router.push() calls in practice pages
- Add scroll={false} to Link component in not-found page
- Fixes Next.js warning about auto-scroll with fixed position header
- Add mobile-web-app-capable meta tag alongside deprecated apple-mobile-web-app-capable

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 11:25:53 -06:00
Thomas Hallock
43e7db4e88 fix(practice): check all later prefix sums for ambiguity, not just final answer
Previously, typing "3" for problem [2, 1, 30, 10, 1] with prefix sums
[2, 3, 33, 43, 44] would immediately show help for prefix sum 3 because
the code only checked if "3" was a digit-prefix of the final answer (44).

Now it correctly checks if "3" could be a digit-prefix of ANY later prefix
sum (33 in this case), making it ambiguous and allowing the user to continue
typing "33" to get help for that prefix instead.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 10:48:38 -06:00
Thomas Hallock
ed277ef745 feat(practice): refactor disambiguation into state machine with comprehensive tests
- Complete migration of disambiguation state into the state machine
- Remove backward compatibility code (no legacy concerns in new app)
- Eliminate dual-state patterns in ActiveSession.tsx
- Export derived state from hook (attempt, helpContext, outgoingAttempt)
- Export boolean predicates (isTransitioning, isPaused, isSubmitting)
- Add comprehensive tests for awaitingDisambiguation phase
- Fix tests to match actual unambiguous prefix sum behavior
- Add SSR support with proper hydration for practice pages

The state machine is now the single source of truth for all UI state.
Unambiguous prefix matches immediately trigger helpMode, while ambiguous
matches enter awaitingDisambiguation with a 4-second timer.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 10:19:14 -06:00
Thomas Hallock
46ff5f528a feat(practice): add prefix sum disambiguation and debug panel
- Add ProblemDebugPanel component for viewing current problem details
  when visual debug mode is enabled (fixed position, collapsible, copy JSON)

- Fix false positive help mode triggers when typing multi-digit answers
  - "3" when answer is "33" now shows "need help?" prompt instead of
    immediately triggering help mode
  - 4 second timer before auto-triggering help in ambiguous cases

- Add leading zero disambiguation for requesting help
  - Typing "03" explicitly requests help for prefix sum 3
  - isDigitConsistent now allows leading zeros
  - findMatchedPrefixIndex treats leading zeros as unambiguous help request

- Add "need help?" styled pill prompt on ambiguous prefix matches
  - Yellow pill badge with arrow pointing to the term
  - Pulse animation for visibility

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 09:32:27 -06:00
Thomas Hallock
36c9ec3301 fix(practice): handle paused state transitions and add complete phase
Fix edge cases in the state machine:
- completeSubmit now works while paused (updates resumePhase)
- completeTransition now works while paused (updates resumePhase)
- Add 'complete' phase for session completion
- Allow enterHelpMode from helpMode (navigate between terms)
- Add transformActivePhase helper for paused state handling
- Add markComplete action and isComplete predicate
- Prevent pausing from complete phase

Add 5 new tests for these edge cases.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 15:47:47 -06:00
Thomas Hallock
1ce448eb0b refactor(practice): clean up props for state machine compatibility
- NumericKeypad: add showSubmitButton prop to hide submit during auto-submit
- VerticalProblem: remove autoSubmitPending prop (state machine handles this)
- Add usePracticeSoundEffects hook for centralized sound effect management

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 15:28:03 -06:00
Thomas Hallock
4d41c9c54a refactor(practice): replace boolean flags with state machine
Replace scattered boolean state flags (isPaused, isSubmitting, isTransitioning,
feedback, helpTermIndex) with a single discriminated union state machine.

- Add useInteractionPhase hook with 7 explicit phases:
  loading, inputting, helpMode, submitting, showingFeedback, transitioning, paused
- Derive all UI predicates from phase state (canAcceptInput, showHelpOverlay, etc.)
- Delete useProblemAttempt hook (superseded by state machine)
- Add 62 comprehensive tests for phase transitions and derived state

Benefits:
- Single source of truth for all interaction state
- Impossible states eliminated (can't be paused AND submitting)
- Explicit phase transitions instead of scattered boolean flipping
- Type safety ensures phase-appropriate data access

Both vertical and linear problem formats use the same state machine.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 15:28:03 -06:00
Thomas Hallock
e937c05323 chore: miscellaneous updates and documentation
- Update know-your-world implementation docs
- Update decomposition CSS styles
- Update AbacusReact component
- Update gallery template
- Update dependencies (pnpm-lock.yaml)
- Update biome config

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 11:40:59 -06:00
Thomas Hallock
b56c8f439b refactor(practice): add centralized style system for practice components
Add new style utilities to reduce duplication and improve maintainability:
- practiceTheme.ts: Color definitions with light/dark variants and themed() helper
- practiceStyles.ts: Reusable style functions (cards, buttons, badges, progress bars)
- practiceMixins.ts: Layout primitives (centerStack, row, gap/padding presets)
- index.ts: Central export for all utilities

Migrate NumericKeypad and StudentSelector as proof of concept.
Also fix StudentSelector.stories.tsx invalid isGuest property.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 11:29:25 -06:00
Thomas Hallock
4c00d92ccb fix(practice): use explicit padding to prevent shorthand override
Replace padding shorthand with explicit paddingTop/Right/Bottom/Left
values to ensure the extra 4rem top padding for help overlays is
applied correctly. CSS shorthand properties can override specific
properties depending on declaration order.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 11:14:02 -06:00
Thomas Hallock
e9b123a7b3 fix(practice): remove overflow clipping to allow help overlays
Remove overflow-x/overflow-y clipping as CSS doesn't allow mixing
visible and hidden on different axes. The outgoing problem fades
to opacity 0 anyway so clipping isn't needed.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 11:07:05 -06:00
Thomas Hallock
1ddf9fc94f fix(practice): allow vertical overflow for help overlays
Change overflow: hidden to overflowX: hidden + overflowY: visible
so help elements above the problem are not clipped while still
hiding horizontal transition animation overflow.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 09:57:58 -06:00
Thomas Hallock
b12112e8da feat(practice): add smooth problem transition animation
- Add react-spring animation for transitioning between problems
- New problem fades in to the right, then track slides left to center it
- Outgoing problem fades out during the slide
- Use useLayoutEffect to prevent layout jank from flexbox recentering
- Use flushSync for smooth cleanup when removing outgoing problem
- Hide decomposition section when not meaningful (e.g., "5 = 5")
- Add DecompositionSection component for self-contained display
- Simplify HelpAbacus visibility with opacity + pointer-events

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 09:56:51 -06:00
Thomas Hallock
52ea3f10fa fix(practice): prevent decomposition math from wrapping
Add whiteSpace: 'nowrap' to keep the step-by-step math on one line.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 06:41:46 -06:00
Thomas Hallock
88a2b82f55 refactor(practice): remove usePracticeHelp hook and progressive help levels
We no longer use progressive help levels - help shows all at once when
a prefix sum is detected. Removed:
- usePracticeHelp hook and all helpState/helpActions usage
- helpSettings and isBeginnerMode props
- currentTermIndex state (unused after help system removal)
- handleDismissHelp callback (unused)
- Help tracking fields from result (helpLevelUsed, helpTrigger)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 06:37:20 -06:00
Thomas Hallock
10c210c3b1 refactor(practice): simplify submit button, remove unused help button state
Since help auto-triggers when a prefix sum is detected, the "Get Help"
button state was never actually usable. Simplified to just Submit/disabled.

- Replace buttonState ('help'|'submit'|'disabled') with canSubmit boolean
- Remove handleGetHelp callback (auto-help useEffect handles it)
- Button now always shows "Submit" or "Enter Total"

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 06:26:39 -06:00
Thomas Hallock
b46a99a3a1 refactor(practice): remove part instruction banner
The part type is already shown in the HUD - redundant banner removed.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 21:05:56 -06:00
Thomas Hallock
e9ccfb9186 fix(practice): remove redundant 'already at target' message
Return null instead of showing message when target is reached -
the success feedback is already shown elsewhere in the component.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 20:59:01 -06:00
Thomas Hallock
19169ad9fe feat(practice): improve help UX with coach hints and simplified UI
- Add coach hint generator using same hints as tutorial (segment.readable.summary)
- Hide abacus numerals in help mode for cleaner display
- Restructure layout: abacus centered, coaching panel on right side
- Exit help mode completely when student finishes adding term to abacus
- Remove checkmarks from term indicators, keep only arrow for current term
- Clean up unused props (confirmedTermCount, detectedPrefixIndex, countdownElement)
- Add HelpCountdown component (pie chart timer, not currently used)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 20:41:33 -06:00
Thomas Hallock
9a4ab8296e feat(practice): add progressive help overlay with proper positioning
- Create PracticeHelpOverlay component showing interactive abacus with
  bead arrows and tooltips (uses same system as TutorialPlayer)
- Extract BeadTooltipContent to shared component for consistency
- Add helpOverlay prop to VerticalProblem for proper positioning
- Position help abacus directly above the term being helped using
  bottom: 100% on the term row (overflow visible)
- Dynamically size abacus columns based on max(currentValue, targetValue)
- Add timing configuration in helpTiming.ts (debug vs production)
- Add beadTooltipUtils.ts for tooltip positioning calculations

The help overlay now correctly covers the confirmed terms in the
vertical problem, with the "Adding: +X" badge and interactive abacus
positioned above the term being worked on.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 15:38:17 -06:00
Thomas Hallock
804d937dd9 feat(practice): integrate progressive help with decomposition display
- Extract standalone DecompositionContext from TutorialContext
- Create reusable DecompositionDisplay and ReasonTooltip components
- Wire prefix-sum "Get Help" button to progressive help system (L1→L2→L3)
- Sync abacus interactions with decomposition step highlighting
- Add currentStepIndex tracking in PracticeHelpPanel
- Make HelpAbacus interactive at L3 to update decomposition display
- Update documentation linking decomposition components

The progressive help system now:
- L1: Shows coach hint when user clicks "Get Help" after typing prefix sum
- L2: Shows interactive decomposition with hoverable explanations
- L3: Shows visual abacus with arrows, synced with decomposition highlighting

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 08:56:35 -06:00
Thomas Hallock
2f7cb03c3f feat: add auto-submit on correct answer + Newton poem blog post
Practice session improvements:
- Auto-submit when correct answer entered with ≤2 corrections
- Show celebration animation ("Perfect!") before auto-submit
- Display prefix sum checkmarks/arrows before clicking "Get Help"

New blog post: "The Fluxion of Fortune"
- Poem about Newton losing money in the South Sea Bubble
- Hero image of Newton with his calculations and sinking ships
- Custom CSS for properly centered x-bar notation

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 06:46:12 -06:00
Thomas Hallock
026993cb05 feat(practice): add dark mode support and fix doubled answer digits
- Add dark mode support to all practice components:
  - ActiveSession, VerticalProblem, NumericKeypad, HelpAbacus
  - StudentSelector, ProgressDashboard, PlanReview, SessionSummary
  - OfflineSessionForm, ManualSkillSelector, PlacementTest, PracticeHelpPanel
- Fix doubled answer digit cells in VerticalProblem by consolidating
  two separate cell-rendering loops into a single unified loop

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 19:59:23 -06:00
Thomas Hallock
a50b268d35 fix(practice): add 80px top padding to account for app nav height
Push main content down below the fixed app navigation bar.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 19:20:47 -06:00
Thomas Hallock
b19c6d0eca feat(practice): add session HUD with tape-deck controls and PageWithNav
Major UI improvements to the practice session:
- Add dark control bar at top with session info and transport controls
- Replace pause/end buttons with tape-deck style buttons (⏸️/▶ and ⏹️)
- Move part type, problem count, and progress info into compact HUD
- Add overall progress counter (X/Y total) and health indicator
- Wrap practice page with PageWithNav for consistent app navigation
- Begin dark mode support with isDark prop from useTheme

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 19:16:13 -06:00
Thomas Hallock
871390d8e1 feat(help-system): add focus areas for skills needing reinforcement
Add tracking and display of skills that need extra practice:
- Add needsReinforcement, lastHelpLevel, reinforcementStreak to SkillProgress
- Add Focus Areas section to ProgressDashboard
- Add teacher controls to clear reinforcement flags
- Simplify helpSettings schema (remove default value from schema)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 19:12:13 -06:00
Thomas Hallock
3ce12c59fc feat(abacus-react): add defaultValue prop for uncontrolled mode
Add standard React controlled/uncontrolled component pattern to AbacusReact:
- Add `defaultValue` prop to support uncontrolled mode (component owns state)
- When `value` is provided, component operates in controlled mode (syncs to prop)
- When only `defaultValue` is provided, component operates in uncontrolled mode
- Update HelpAbacus to use defaultValue for interactive help

This enables interactive abacus in help mode where the component tracks its own
state while parent monitors via onValueChange callback.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 19:11:43 -06:00
Thomas Hallock
373ec34e46 feat(help-system): integrate PracticeHelpPanel into ActiveSession
Phase 3 of help system implementation:

New component:
- PracticeHelpPanel.tsx: Progressive help display for practice sessions
  - L0: "Need Help?" button
  - L1: Coach hint with verbal guidance
  - L2: Mathematical decomposition with segment explanations
  - L3: Bead movement steps with instructions
  - Help level indicator dots
  - "More Help" escalation button
  - Max help level tracking display

ActiveSession integration:
- Added usePracticeHelp hook for help state management
- Track running total and current term for help context
- Reset help context when advancing to new term
- Record help usage in SlotResult (helpLevelUsed, incorrectAttempts, helpTrigger)
- Display PracticeHelpPanel after problem, before input area
- Pass isAbacusPart to enable bead-specific help messaging

Props added:
- helpSettings: StudentHelpSettings for configurable help behavior
- isBeginnerMode: Enable free help without mastery penalty

Stories updated:
- Fixed Date timestamp types
- Added default help tracking fields in interactive demo

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 15:27:51 -06:00
Thomas Hallock
0b1ad1f896 feat(help-system): add usePracticeHelp hook and skill extraction
Phase 2 of help system implementation:

New utilities:
- skillExtraction.ts: Maps pedagogical rules to SkillSet identifiers
  - extractSkillsFromSequence(): Extract skills from instruction sequence
  - extractSkillsFromProblem(): Extract skills for multi-term problems
  - getUniqueSkillIds(): Get deduplicated skill list
  - Helper functions for skill ID parsing

New hooks:
- usePracticeHelp.ts: Manages progressive help during practice
  - L0-L3 help levels (none → hint → decomposition → bead arrows)
  - Timer-based auto-escalation in 'auto' mode
  - Error-based auto-escalation (2+ errors triggers help)
  - Manual help request in 'manual' mode
  - Teacher-approved mode placeholder for L2+ help
  - Generates help content from UnifiedInstructionSequence
  - Tracks maxLevelUsed for feedback loop

Test coverage:
- 18 tests for skill extraction covering:
  - Direct addition, heaven bead, simple combinations
  - Five's complement patterns (4=5-1, 3=5-2, 2=5-3, 1=5-4)
  - Ten's complement patterns (9=10-1 through 5=10-5)
  - Multi-digit additions with multiple skills
  - Multi-term problem skill extraction

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 15:21:22 -06:00
Thomas Hallock
41c46038d8 feat(help-system): add schema for progressive help and feedback loop
Phase 1 of help system implementation:

Schema changes:
- Add HelpLevel type (0-3) to session-plans.ts
- Extend SlotResult with helpLevelUsed, incorrectAttempts, helpTrigger
- Add REINFORCEMENT_CONFIG constants for mastery credit multipliers
- Add reinforcement tracking columns to player_skill_mastery:
  - needsReinforcement: flag for skills needing extra practice
  - lastHelpLevel: track struggling patterns
  - reinforcementStreak: track progress toward clearing reinforcement
- Add StudentHelpSettings interface and column to players:
  - helpMode: 'auto' | 'manual' | 'teacher-approved'
  - autoEscalationTimingMs: configurable help timing thresholds
  - beginnerFreeHelp: unlimited L1-L2 help without penalty
  - advancedRequiresApproval: require teacher auth for L2+ help

This closes the feedback loop between help usage and session planning:
- Help usage informs skill mastery scoring
- Reinforcement flags guide session planner to include extra practice
- Teacher has visibility into which skills need attention

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 15:16:52 -06:00
Thomas Hallock
f153dddfce refactor(nav): replace Guide with Practice in main nav
- Main nav bar now shows Practice instead of Guide
- Guide moved to hamburger menu (deprecation path)
- Practice added to hamburger menu for consistency
- Reordered hamburger menu: Home, Create, Practice, Games, Guide, Blog

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 14:28:30 -06:00
Thomas Hallock
b52f0547af feat(practice): add student onboarding and offline sync features
Add three onboarding features for students coming from books/tutors:

1. Placement Test - Adaptive diagnostic quiz with configurable thresholds
   - Tests skills progressively following curriculum order
   - Tracks consecutive correct/wrong to determine mastery level
   - Presets: Quick, Standard, Thorough assessment modes
   - Shows real-time progress and skill-by-skill results

2. Manual Skill Selector - Teacher-controlled skill mastery setting
   - SAI Abacus Mind Math book level presets (Level 1, 2, 3)
   - Accordion UI organized by skill category
   - Checkbox selection for individual skills

3. Offline Session Form - Record practice done outside the app
   - Date picker, problem count, accuracy slider
   - Skill focus dropdown and notes field

Includes Storybook stories for all new components.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 14:04:17 -06:00
Thomas Hallock
585543809a feat(practice): add three-part daily practice session system
Implement complete daily practice session system with:

**Practice Components:**
- StudentSelector: Select which student is practicing
- ProgressDashboard: Show student's current level and progress
- PlanReview: Review and approve generated session plan
- ActiveSession: Main practice UI with three-part structure
- SessionSummary: Show results after session completion
- NumericKeypad: Touch-friendly number input for mobile
- VerticalProblem: Columnar problem display

**Session Structure:**
- Part 1 (Abacus): Physical abacus practice, vertical format
- Part 2 (Visualization): Mental math visualizing beads
- Part 3 (Linear): Mental math with sentence format

**Infrastructure:**
- Database schemas for curriculum, skills, sessions
- Session planner with skill-based problem generation
- React Query hooks for session management
- Consolidated device capability detection hooks
- API routes for curriculum and session management

**Problem Generation:**
- ActiveSession now uses actual skill-based algorithm
- Problems generated with appropriate skills constraints
- Storybook stories use real problem generation

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 12:23:53 -06:00
Thomas Hallock
d00c70750e feat(worksheets): smooth dice rotation settle to final face
Instead of abruptly snapping to the final face, the dice now:
- Gradually lerps rotation toward target face as it approaches home
- Uses cubic easing for natural deceleration
- Normalizes angles for shortest rotation path
- Waits until rotation is within 5° of target before stopping

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 17:32:02 -06:00
Thomas Hallock
c6db7dcfa2 feat(worksheets): add viewport edge ricochet to dice physics
Dice now bounces off viewport edges instead of flying through them:
- Bounce damping (0.7) reduces velocity on each bounce
- Extra spin added on collision for dynamic feel
- Takes scaled dice size into account for accurate edge detection

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 17:14:47 -06:00
Thomas Hallock
047a960567 feat(worksheets): enhance dice throw physics for natural feel
Improvements during drag:
- Live rotation based on drag velocity (dice tumbles while dragging)
- Gradual scale up to 1.5x as you pull further
- Dynamic drop shadow that grows with distance

Improvements during flight:
- Throw power affects gravity (stronger throws fly further)
- Gravity ramps up over time for momentum carry-through
- Quadratic gravity falloff for natural physics
- More dramatic rotation during tumble
- Shadow tied to scale for depth perception
- Slower scale shrink for dramatic return

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 16:42:39 -06:00
Thomas Hallock
920a855eb5 feat(worksheets): add 3x scale effect to thrown dice
When the dice is thrown, it now grows to 3x its normal size while
flying, then smoothly shrinks back to normal as it returns home.
The scaling is center-stable and won't complete until fully shrunk.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 16:29:11 -06:00
Thomas Hallock
b8e66dfc17 feat(worksheets): add draggable dice easter egg with physics
Add a fun easter egg where the dice in the worksheet action menu can be
dragged and thrown. The dice:
- Tracks pointer movement and calculates throw velocity
- Uses physics simulation with gravity pulling back to origin
- Rolls continuously based on movement direction and speed
- Uses direct DOM manipulation for smooth 60fps animation
- Triggers shuffle when thrown and returns home

Also includes worksheet improvements:
- Conditional name field display (hide when empty/default)
- Date positioned top-right next to QR code
- Reduced problem number size
- Tightened header-to-grid spacing
- Problem numbers aligned to cell corners

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 16:24:58 -06:00
Thomas Hallock
a0e73d971b feat(worksheets): add QR codes with share codes for easy worksheet sharing
- Add optional QR code embedding in worksheet PDFs (toggle in Layout settings)
- Display 7-character share code under QR code for manual entry
- Create share record when generating PDF with QR code enabled
- Add "Load Share Code" modal for entering share codes without smartphone
- Update preview to show QR code placement when enabled
- Fix async/await for generateTypstSource across all callers

The QR code appears in the header next to the date, with the share code
printed below it. Users without smartphones can type the code into the
"Load Share Code" option in the worksheet generator menu.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 11:57:49 -06:00
Thomas Hallock
ed25b323e8 fix(create): use inline styles for dynamic gradient backgrounds
Panda CSS's css() function doesn't properly interpolate dynamic gradient
strings. Move background and boxShadow with theme.gradient values to
inline style props for:
- Top gradient bar (converted from _before pseudo to actual div)
- Icon background
- CTA button background

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 10:38:23 -06:00
Thomas Hallock
02463df8e5 fix(worksheets): prevent infinite loop when problem space is empty
Add guards against empty problem space in both addition and subtraction
generators. When constraints are impossible to satisfy (e.g., 1-digit
with 100% borrowing), the generate-all approach would return 0 problems,
causing:
- Subtraction: infinite while loop trying to fill from empty array
- Addition (interpolate): array index -1 crash
- Addition (non-interpolate): division by zero in cycle calculation

All three paths now detect empty arrays and return safe fallback problems
with appropriate error logging instead of hanging the server at 85% CPU.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 10:17:52 -06:00
Thomas Hallock
822ef78e58 fix(worksheets): sync preview and download problem generation
Fix parameter mismatch in generatePreview.ts that caused preview to
show different problems than downloaded PDF:

- Addition: fix parameter order (was digitRange first, should be pAnyStart)
- Addition: add missing interpolate parameter
- Subtraction: add missing interpolate parameter
- Mixed: add missing interpolate parameter

Now preview and download use identical parameters, generating the same
problem set for the same seed.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 10:03:40 -06:00
Thomas Hallock
739303ef5a style(create): improve responsive layout and center cards
Refactor create hub page for better mobile experience:
- Extract reusable CreatorCard component with theme config
- Center 3-card grid properly (was 4-column with 3 cards)
- Responsive breakpoints: 1 col mobile, 2 col tablet, 3 col desktop
- Hide feature lists on very small screens for compact cards
- Scale down icons, fonts, padding, and shadows on mobile
- Reduce code from 688 to ~310 lines

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 10:00:52 -06:00
Thomas Hallock
cdd0de797f fix(worksheets): render operators last for proper layering
Use Typst's place() function to overlay + and − operators on top of
all other problem elements. This ensures operators are always visible
and properly layered over carry/borrow boxes, scratch work, and other
decorations.

Changes:
- Addition: wrap grid in box, use place() for + sign overlay
- Subtraction: extract operator to operatorOverlay.ts, use place()
- Both operators positioned at correct row using dy offset

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 09:46:46 -06:00
Thomas Hallock
2ae5fbfac9 refactor(worksheets): migrate dice animation to react-spring
Replace CSS keyframe-based dice animation with react-spring for smoother
physics-based animation:

- Use spring physics instead of baked quadratic ease-out keyframes
- Track spin count and target face for reliable face landing
- Ensure dice always shows 2-6 (never 1), never consecutive same number
- Face number is deterministic based on seed
- Add dark/light mode theming with distinct color schemes:
  - Light: deep indigo (#4f46e5) with white dots
  - Dark: light indigo (#818cf8) with dark indigo dots

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 09:41:50 -06:00
Thomas Hallock
3cd5e4992b feat(worksheets): upgrade to 3D dice with random rotation animation
- Replace 2D SVG dice with CSS 3D cube using transform-style: preserve-3d
- Each face shows correct dot pattern (1-6) with proper dice layout
- Random rotation direction and spin count on each shuffle
- Quadratic ease-out for realistic deceleration (settles naturally)
- Opaque faces to prevent render artifacts during rotation
- WebKit backface-visibility for cross-browser support

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 09:33:30 -06:00
Thomas Hallock
f97efb5c94 feat(worksheets): add shuffle button with animated dice icon
Add a shuffle button to the worksheet preview floating action bar that
generates a new random seed for problem generation:

- 1/3 split button design: [Download] [🎲] [▼ dropdown]
- Animated dice that rolls and changes faces (2-6) during regeneration
- Final dice face derived from seed, never lands on same number twice
- Excludes face 1 to ensure the icon is clearly recognizable as a dice

Also includes attempted fix for operator layering in Typst templates
(changed operator box width to 0.5em).

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 09:17:49 -06:00
Thomas Hallock
4449fb19b4 feat(know-your-world): improve mobile magnifier controls and animations
- Add animated expand/collapse transitions using react-spring for smooth magnifier resizing
- Maintain 20px margin around expanded magnifier to allow clicking outside to dismiss
- Add close button (X) to magnifier controls for dismissing the magnifier entirely
- Replace "Full Map" text button with expand/collapse icons
- Animate button visibility with opacity transitions instead of instant show/hide
- Add width/height to MagnifierSpring for animated size transitions

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 08:39:52 -06:00
Thomas Hallock
17c113e68b fix(know-your-world): raise auto-zoom thresholds for tiny regions
Increase the max acceptance thresholds so sub-pixel regions like Gibraltar,
Vatican City, and Monaco get maximum zoom instead of being rejected:

- Sub-pixel (<1px): 2-8% → 2-40% (allows 1000x zoom)
- Tiny (1-5px): 5-15% → 5-25%
- Normal small: 10-25% → 10-30%

Previously, at 1000x zoom a 0.08px region would occupy ~20% of the magnifier,
exceeding the 8% max threshold. The algorithm would then step DOWN trying to
find a zoom where it fits within 2-8%, making tiny regions harder to select.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 08:16:59 -06:00
Thomas Hallock
e4c35e9425 fix(know-your-world): use shared MAX_ZOOM constant for mobile magnifier
Replace local MAX_ZOOM = 50 with shared MAX_ZOOM = 1000 from constants.
This fixes mobile magnifier auto-zoom being incorrectly capped at 50x
when panning within the magnifier, while map dragging was uncapped.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 07:56:05 -06:00