Commit Graph

3365 Commits

Author SHA1 Message Date
Thomas Hallock e703e90875 chore: cleanup unused imports and apply formatting
- Remove unused `and` import from VisionRecorder.ts
- Remove unused `IncomingMessage` and `ws` imports from socket-server.ts
- Add `muted` attribute to video element in ProblemVideoPlayer
- Apply code formatting across vision and practice components
- Update documentation formatting in DEPLOYMENT.md and README

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 18:49:31 -06:00
Thomas Hallock cecd1e93e2 fix(practice): handle loading phase in activeProblem effect
The useInteractionPhase effect now handles two cases:
1. activeProblem.key changes (redo mode, navigation, session advances)
2. Phase becomes 'loading' (after incorrect answer or part transition)

Previously, only key changes triggered problem loading, which caused
"Loading next problem..." to persist after incorrect answers since
clearToLoading() sets phase to 'loading' without changing the key.

Also adds debug logging for part transitions and game breaks.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 18:32:39 -06:00
Thomas Hallock 4733149497 chore: update local Claude settings
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 17:50:00 -06:00
Thomas Hallock 95b209e471 style: apply formatting to vision and practice components
Minor whitespace/line-wrapping adjustments.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 17:49:55 -06:00
Thomas Hallock 2f06ed3bbf test(players): add unit tests for useUserPlayers optimistic updates
Tests cover:
- useCreatePlayer optimistic updates to list() and listWithSkillData()
- Graceful degradation when listWithSkillData isn't cached
- Rollback on server errors and network failures
- Cache invalidation on success/error
- API integration (correct endpoint, request body)
- useUpdatePlayer optimistic updates and rollback
- useDeletePlayer optimistic delete and rollback

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 17:43:38 -06:00
Thomas Hallock 72c4825333 feat(players): add optimistic update for listWithSkillData
When creating a new player, optimistically update both the player list
and the listWithSkillData query (used by /practice page). This makes
new players appear immediately without requiring a page reload.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 17:35:22 -06:00
Thomas Hallock 71e9345d2a fix(players): invalidate all player queries on create/delete
useCreatePlayer and useDeletePlayer were only invalidating
playerKeys.lists() which doesn't include listWithSkillData().

The practice page uses usePlayersWithSkillData() so newly created
players weren't appearing until page reload.

Now invalidates playerKeys.all to catch all player-related queries.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 17:20:09 -06:00
Thomas Hallock eefa4e8d71 fix(vision): show disabled Enable Vision button with explanation
Instead of hiding the "Enable Vision" button when setup isn't complete,
show it disabled with an explanation of what's needed:
- "Waiting for camera access..." for local camera
- "Connect your phone to enable vision" for phone camera

This provides better UX feedback about what the user needs to do.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 17:18:24 -06:00
Thomas Hallock 4cace475b9 fix(vision): infer activeCameraSource from existing config
When loading vision config from localStorage, infer activeCameraSource
if it's null but cameraDeviceId or remoteCameraSessionId is set.

This fixes a bug where the "Enable Vision" button wouldn't appear
until the user clicked "This Device" or "Phone Camera", even if
they had previously configured vision before activeCameraSource
was added to the config schema.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 17:17:20 -06:00
Thomas Hallock b47992f770 feat(deploy): add blue-green deployment with health endpoint
- Add /api/health endpoint that checks database connectivity
- Set up blue-green deployment with two containers (abaci-blue, abaci-green)
- Add docker-compose.yaml with YAML anchors for DRY config
- Add generate-compose.sh to create blue/green compose files from main
- Update deploy.sh with NAS-specific fixes (scp -O, PATH for docker)
- Fix deploy.sh to not overwrite production .env by default

The blue-green setup allows zero-downtime deployments via compose-updater,
which watches separate compose files and restarts containers independently.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 17:04:01 -06:00
Thomas Hallock b08a796058 fix(observe): show banner with link instead of auto-redirect
- Change from automatic redirect to persistent banner with link
- Authenticated observation: show "session ended" banner with link to report
- Public observation: show banner with link if user has view access
- Remove auto-redirect behavior per user feedback

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 12:38:55 -06:00
Thomas Hallock 66acd0c7c9 feat(observe): redirect to session report when session is over
- Authenticated observation page: redirect to session report if completed
- Public observation page: redirect to session report if user has view access
- Show friendly "session ended" page for unauthenticated users on public links
- Prevents 404 for ended sessions when user has access to view the report

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 12:36:17 -06:00
Thomas Hallock a607fce977 fix(vision): add ffmpeg for video encoding and lazy encoding support
- Add ffmpeg to Docker runtime dependencies for encoding vision frames to MP4
- Fix VisionRecorder to mark videos as 'failed' (not 'ready') when ffmpeg unavailable
- Add lazy encoding: when video requested but MP4 missing, encode frames on-demand
- Returns 202 with retryAfterMs so client knows to poll for completion
- Add link to vision markers page from /create hub
- Various vision recording improvements from plan mode work

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 12:30:15 -06:00
Thomas Hallock b5c83b89eb refactor(practice): derive active problem from single source of truth
- Add activeProblem computed value that derives from redoState + currentProblemInfo
- Modify useInteractionPhase to accept activeProblem prop and react to key changes
- Remove synchronization effects that caused redo mode bugs
- Simplify SessionProgressIndicator to compute attempt counts from results directly
- Remove plan prop dependency - both student and observer views now use same code path

This eliminates the dual source of truth (redoState vs phase.attempt.problem) that
was causing synchronization bugs when entering/switching/exiting redo mode.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 11:52:38 -06:00
Thomas Hallock ce8c15f6cf fix: add missing vision recording files
These files were created but never committed:
- VisionDvrControls.tsx - DVR-style playback controls
- VisionRecordingPlayer.tsx - video player component
- useSessionRecording.ts - recording data fetching hook
- cleanupVisionRecordings.ts - cleanup script
- ObserverVisionFeed.stories.tsx - storybook stories

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 09:34:23 -06:00
Thomas Hallock e368a66b5f fix: add missing vision-recordings schema file
The TypeScript schema file was never committed, causing build failures.
The migration (0067) that creates the table was already committed.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 09:27:15 -06:00
Thomas Hallock a5f5179a57 feat(debug): add socket debug panels for practice and observer pages
Add visual debug panels that show socket connection state when the
"visual debug" toggle is enabled in the app nav:

- BroadcastDebugPanel: Shows on student practice page with socket
  connection status, broadcast state, recording status, and current
  problem info

- ObserverDebugPanel: Shows on observer page with connection status,
  observed state, vision frame info, DVR buffer info, and error messages

Both panels are fixed at bottom-left, collapsible, and include
JSON copy buttons for easy bug reporting.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 09:10:33 -06:00
Thomas Hallock 5ee18d6f74 fix(socket): handle already-connected socket in session hooks
When socket.io-client reuses an existing Manager that's already connected,
the 'connect' event doesn't fire for new Socket instances. This caused
session broadcasting and observation to silently fail until the old
connection timed out (~45 seconds).

Fix: After attaching the 'connect' handler, check if socket.connected is
already true and manually trigger the connect logic.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 08:40:38 -06:00
Thomas Hallock 9b86739b46 feat(vision): add multi-attempt recording support for epoch retries and manual redos
- Add epoch/attempt tracking to vision_problem_videos schema (epochNumber, attemptNumber, isRetry, isManualRedo)
- Update VisionRecorder filename pattern to include epoch/attempt: problem_NNN_eX_aY.mp4
- Fix getRetryContext to use correct slot indices during manual redos
- Add answer-submitted marker for redo problems via handleRecordRedo wrapper
- Create attempt-tracking.ts utility for video attempt grouping and labeling
- Add attempt selector dropdown to ProblemVideoPlayer when multiple attempts exist
- Update API routes to accept epoch/attempt query params for video and metadata
- Add comprehensive documentation for vision recording system (README.md)

Multiple attempts at the same problem (from epoch retry rounds or manual redo clicks)
now save separate recordings instead of overwriting each other.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 07:55:24 -06:00
Thomas Hallock fbbbf9f50b fix(vision): fix problem video recording when camera starts mid-session
- Add effect to emit problem-shown marker when recording starts, ensuring
  the current problem gets a video entry even if camera was enabled late
- Improve DockedVisionFeed UX: show session ID, action buttons immediately
  for remote camera connections (not just after 15s timeout)
- Add .prettierignore to prevent prettier from corrupting Panda CSS
  generated styled-system directory
- Document styled-system fix procedure in CLAUDE.md

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 18:56:21 -06:00
Thomas Hallock 371b449d15 feat(vision): implement per-problem video recording for teacher playback
Add server-side per-problem video recording that allows teachers to click
on completed problems in the observer progress indicator to watch recorded
videos of each problem attempt.

Key changes:
- New vision_problem_videos schema and migration for per-problem videos
- VisionRecorder refactored for per-problem frame management
- Socket server triggers ffmpeg encoding on problem transitions
- API routes for streaming videos and listing available recordings
- SessionObserverModal enables browse mode on progress indicator
- ProblemVideoPlayer component for viewing past problem recordings

Each problem gets its own MP4 video encoded incrementally as it completes,
making playback immediately available for recently completed problems.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 18:21:54 -06:00
Thomas Hallock 87112c0235 feat(vision): add per-problem DVR scrubbing for teacher observation
- Add 'problem-shown' marker emission when new problems appear in practice
- Track currentProblemStartMs in VisionRecorder for each session
- Update vision-buffer-info socket event to include problem context
- Constrain DVR scrubber to current problem range only
- Auto-reset to live view when student moves to next problem
- Move DVR controls below video for better usability
- Fix QR code being cut off by removing overflow:hidden from containers
- Add QueryClientProvider to Storybook for React Query components
- Add comprehensive stories for ObserverVisionFeed with DVR states

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 17:33:47 -06:00
Thomas Hallock 7d2756e3d7 feat(scoreboard): add skills metrics with classroom leaderboard
Add comprehensive skill metrics to the scoreboard that allow comparing
students across a classroom with "fun ways to compare across ability levels":

Skills Progress Section (individual view):
- Overall mastery % (weighted by BKT confidence)
- Category breakdown (basic, fiveComplements, tenComplements, etc.)
- Speed metric (normalized seconds per term) with trend arrows
- Accuracy with trend indicators
- Weekly/streak/total problem counts

Classroom Achievements Section (fair comparisons):
- Practice Warriors: most problems this week
- Streak Masters: longest practice streak
- Rising Stars: highest improvement rate (pKnown delta/week)
- Speed Champions: fastest per category (only mastered students compete)

Also includes:
- Remote camera session validation to prevent stale sessions
- Comprehensive Storybook stories for all skill metrics components

New files:
- src/lib/curriculum/skill-metrics.ts (core computation)
- src/app/api/curriculum/[playerId]/skills/metrics/route.ts
- src/app/api/classroom/[classroomId]/skills/leaderboard/route.ts
- src/hooks/useSkillMetrics.ts (React Query hooks)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 13:13:21 -06:00
Thomas Hallock f8861e6f8d fix(scripts): import classroom functions directly to fix build
The barrel export from @/lib/classroom pulls in all manager modules,
some of which have transitive dependencies on React components with
styled-system imports. Import directly from the specific manager files
(classroom-manager.ts and enrollment-manager.ts) to avoid the
dependency chain that breaks esbuild bundling for the seed script.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 11:38:21 -06:00
Thomas Hallock c587caaaae fix(scoreboard): use student's enrolled classroom for leaderboard
The scoreboard was incorrectly using the teacher's classroom instead of
the student's enrolled classroom. Now uses useEnrolledClassrooms hook
to get the student's classroom membership for the leaderboard display.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 11:34:12 -06:00
Thomas Hallock e419725037 feat(seeding): add classroom enrollment for test students
- Create classroom for current user if they don't have one
- Enroll all seeded test students in the teacher's classroom
- Enables testing of classroom leaderboard features

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 11:27:30 -06:00
Thomas Hallock d258c267f5 fix(scoreboard): handle ISO string dates in formatRelativeTime
Dates serialized through JSON API come back as ISO strings, not Date objects.
Updated formatRelativeTime to handle string | number | Date inputs.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 11:16:13 -06:00
Thomas Hallock 71efc2c096 chore: update local Claude settings permissions
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 10:50:18 -06:00
Thomas Hallock 12c95c92fa data(vision): add boundary frame training data
Captured frames for boundary detector training

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 10:49:58 -06:00
Thomas Hallock 9fa95eca89 chore: update tsconfig, plans, lockfile, and templates
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 10:49:34 -06:00
Thomas Hallock ba7cdb7044 feat(core): update schema, hooks, and socket server
- Update scanner settings schema
- Update remote camera hooks
- Update socket server and vision session API

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 10:49:24 -06:00
Thomas Hallock 534192f60f chore(models): update boundary detector and column classifier models
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 10:49:19 -06:00
Thomas Hallock 4f812d4ad0 feat(arcade): update matching game and manifest schema
Updates to game break configuration and manifest validation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 10:49:13 -06:00
Thomas Hallock b197d8f035 feat(practice): update practice session components and APIs
Updates to session plans, attempt history, and game break configuration

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 10:49:08 -06:00
Thomas Hallock f45dc8b7f3 feat(vision): update vision training components and APIs
Updates to boundary detection, sync status, and data panel components

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 10:49:03 -06:00
Thomas Hallock 7e3932ae5f feat(queries): add game results query keys for scoreboard
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 10:48:57 -06:00
Thomas Hallock c182756b80 feat(seeding): add game results generation to test student profiles
- Add gameHistory configs to all 21 test student profiles
- Implement generateGameResults function to create scoreboard data
- Each profile has appropriate game history matching their characteristics:
  - Struggling students get low scores (35-45)
  - Developing students get medium scores (55-75)
  - Strong students get high scores (78-95)
- Add accuracyMultiplier to TuningAdjustment interface (fixes TS error)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 10:48:51 -06:00
Thomas Hallock dda041e014 fix(scoreboard): use valid gray.800 token instead of gray.850
gray.850 is not a valid Panda CSS token, causing the value to be
output as a literal string instead of resolving to a hex color.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 10:48:44 -06:00
Thomas Hallock 17b1749342 feat(dashboard): add scoreboard tab with game results tracking
Add complete game results tracking and scoreboard system:

- Database schema: Add game_results table for storing game outcomes
- API endpoints: Add routes for saving results, player history, and
  classroom leaderboards
- React Query hooks: Add usePlayerGameHistory, usePlayerClassroomRank,
  useSaveGameResult
- ScoreboardTab: New dashboard tab showing personal bests, recent games,
  and classroom rankings
- GameBreakResultsScreen: Interstitial showing results after game breaks
- Integration: Save game results when matching game completes, display
  results before returning to practice

Includes Storybook stories and unit tests for both components.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 10:26:49 -06:00
Thomas Hallock 706dbce6f5 feat(practice): add attempt history panel with result editing
Add AttemptHistoryPanel component for browse mode that displays all
attempts (original + retries) for each problem slot. Teachers/parents
can now:

- Mark incorrect attempts as correct (for typo fixes)
- Exclude attempts from progress tracking
- Re-include previously excluded attempts

Technical changes:
- New ResultWithGlobalIndex type for tracking result indices
- Extended SlotResultSource with 'teacher-corrected' and 'teacher-excluded'
- New PATCH API endpoint for editing individual results
- updateSessionPlanResults() function in session-planner
- Query invalidation on result edits

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 07:19:04 -06:00
Thomas Hallock 94be27bc06 fix(practice): use findMatchedPrefixIndex in handleSubmit for docked abacus
When abacus is docked, handleSubmit was using indexOf() to check if the
user's answer matched a prefix sum. This failed when an intermediate
prefix sum equaled the final answer (e.g., 65-34-15+33-18=31 where
prefixSums=[65,31,16,49,31]). indexOf(31) returns 1, triggering help
mode instead of accepting the correct answer.

Now uses findMatchedPrefixIndex() which correctly checks if the answer
equals the final answer FIRST before looking for intermediate matches.

Adds regression tests for this edge case.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 20:44:12 -06:00
Thomas Hallock b4b1090281 feat(practice): add game break preconfiguration UI (Phases 1-3)
Phase 1 - Foundation:
- Extended PracticeBreakConfig type with suggestedConfig, lockedFields, difficultyPresets
- Added PracticeBreakOptions and PracticeBreakGameConfig types
- Extended GameBreakSettings with gameConfig field

Phase 2 - Game Integration:
- Added practiceBreakConfig to matching, memory-quiz, card-sorting manifests
- Implemented getInitialStateForPracticeBreak in game validators
- Set practiceBreakReady: false until full integration complete

Phase 3 - Teacher Configuration UI:
- Added GameBreakDifficultyPresets component (Easy/Medium/Hard presets)
- Added GameBreakCustomConfig component (per-field customization)
- Extended StartPracticeModalContext with game config state
- Integrated presets and customize into GameBreakSettings

Test Coverage:
- 23 context tests for game config state
- 8 component tests for GameBreakDifficultyPresets
- 12 component tests for GameBreakCustomConfig
- 7 Storybook stories for manual testing

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 19:06:39 -06:00
Thomas Hallock 6eddd75536 fix(vision): add JPG support to boundary detector sync
The boundary detector saves images as either PNG or JPG depending on the
camera source format, but the sync system only looked for PNG files. This
caused 3000+ JPG boundary frames on production to be invisible to sync.

Changes:
- SSH find pattern now includes *.png and *.jpg for boundary-detector
- countLocalData counts both PNG and JPG for boundary-detector
- listLocalFiles lists both extensions for boundary-detector
- rsync progress regex matches both extensions

Column classifier remains PNG-only as intended.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 17:50:51 -06:00
Thomas Hallock a8df139a00 fix(arcade): add missing practiceBreakReady field to game manifests
Add practiceBreakReady: false to all game manifests that were missing it.
This field is required by the GameManifest type after it was added for
practice session game break support.

Affected games:
- card-sorting
- complement-race
- know-your-world
- memory-quiz
- rithmomachia
- yjs-demo

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 17:39:37 -06:00
Thomas Hallock ed93c36f52 feat(matching): add responsive compact layout for practice game breaks
- Add GameLayoutContext to control StandardGameLayout behavior
- Container mode uses 100% height (no viewport sizing) for practice breaks
- SetupPhase detects compact mode and hides verbose descriptions/hints
- Add data attributes to all SetupPhase elements for debugging
- Add Storybook stories for matching game in practice context

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 17:21:43 -06:00
Thomas Hallock 32d23d026d feat(practice): improve game break duration selector as time continuum
- Add fill indicator track that animates to selected position
- Use dramatic typography progression (font-size and weight increase)
- Position track at bottom as baseline, not through text
- Export GameInfo type from context for consistent typing
- Combine label and toggle into single clickable element
- Add gaming-inspired gradient backgrounds and glow effects

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 16:27:05 -06:00
Thomas Hallock 54ca5e4f02 feat(practice): add test coverage and storybook for game break UI modes
- Add unit tests for single-game scenario (hasSingleGame, singleGame, auto-selection)
- Add GameBreakSettings tests for single-game UI mode
- Add initialExpanded and practiceApprovedGamesOverride props for Storybook
- Update stories to properly demonstrate both single-game and multi-game UI
- Increase expanded panel maxHeight from 520px to 620px for multi-game UI

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 16:04:14 -06:00
Thomas Hallock a12df6b332 feat(arcade): add shortName field to game manifest
Replace hacky .replace(' Battle', '').replace(' Lightning', '') calls
with a proper shortName field that games can define for compact UI spaces.

- Add optional shortName to GameManifestSchema
- Update matching game with shortName: 'Matching Pairs'
- Use shortName || displayName in GameBreakSettings

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 15:49:04 -06:00
Thomas Hallock b58a0eeca9 feat(practice): add game break indicators and simplify single-game UI
Game Break Progress Indicators:
- Add game break countdown badge to practice nav (shows "3 until 🎮")
- Display specific game icon when a game is selected (not random)
- Show game icon and name in game break HUD header

Practice-Approved Games:
- Add practiceBreakReady flag to game manifest schema
- Games must opt-in via manifest AND be whitelisted
- Currently only Matching Pairs is practice-break ready

StartPracticeModal Refactoring:
- Extract state management to StartPracticeModalContext
- Create sub-components: DurationSelector, PracticeModesSelector,
  GameBreakSettings, MaxTermsSelector, TutorialCTA, RemediationCTA,
  StartButton, ErrorDisplay, SessionConfigSummary
- Add comprehensive unit tests for context and sub-components

Single-Game Mode UI:
- Simplified GameBreakSettings when only one game available
- Shows game icon + name inline with compact duration selector
- Removes unnecessary selection mode toggle and dropdown
- Adds "More games coming soon!" teaser

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 15:46:00 -06:00
Thomas Hallock 93a25c1e7b feat(vision): enhance quad detection with Hough lines and multi-strategy preprocessing
- Add Hough line detection for improved edge finding with finger occlusion
- Implement multi-strategy preprocessing (standard, enhanced, adaptive, multi)
- Add configurable parameters for Canny thresholds, adaptive threshold, morph gradient
- Refactor useDocumentDetection hook with cleaner API
- Add OpenCV type definitions and async loading improvements
- Add loader test pages for debugging OpenCV initialization
- Add quad-test page for interactive detection testing
- Add document detection research notes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 11:16:06 -06:00