β οΈ Unofficial Fan Project β’ No affiliation with Wizards of the Coast, Magic: The Gathering, or Hasbro β’ All card data from Scryfall API
A sophisticated yet simple Magic: The Gathering card scanner that captures cards through your device camera, uses advanced OCR to recognize collector numbers, and builds your digital collection with intelligent foil detection and multi-collection management.
- π± Advanced Camera Integration: Full viewport display with adjustable frame sizing and visual guides
- π’ Language-Independent Recognition: Uses collector numbers for universal card identification across all MTG languages
- π― Smart OCR Engine: Multi-strategy fallback system with specialized foil card detection
- β¨ Automatic Foil Detection: AI-powered image analysis to distinguish foil from normal cards
- πΈ Upload Support: Scan existing photos in addition to live camera capture
- π¦ Flash Control: Automatic flash detection and toggle for optimal lighting
- ποΈ Multi-Collection Support: Create, manage, and switch between unlimited collections
- π·οΈ Smart Card Tracking: Separate foil and normal versions with quantity management
- π Language Detection: Automatic language recognition and display (English, German, French, etc.)
- π Collection Analytics: Real-time card counts and collection statistics
- πΎ Robust Data Storage: Local storage with automatic migration and backup systems
- π€ Moxfield Export: Generate CSV files compatible with popular MTG platforms
- π Adjustable Frame Size: Customize scanning area for different card sizes and distances
- π Visual Foil Effects: Modal UI reflects foil status with shimmer effects
- π Smart Notifications: Contextual success, warning, and error messages
- π± Mobile-First Design: Optimized for phones with responsive desktop support
- π οΈ Debug Mode: Advanced troubleshooting tools for OCR analysis
- β‘ Performance Optimized: Image caching and lazy loading for smooth operation
Traditional MTG scanners struggle with card names due to:
- Language dependencies (German, English, French variations)
- Stylized fonts that confuse OCR
- Complex fuzzy matching algorithms
- False positives from similar names
MTG Scanner uses collector numbers instead:
- β Language Independent: Collector numbers are standardized globally
- β Exact Matching: No fuzzy search needed - precise API lookups
- β Better OCR Target: Simple numbers are easier to recognize than stylized text
- β Unique Identification: Every card has a unique set/number combination
- β Simpler Processing: Single optimized image pipeline
- Modern web browser with camera support (Chrome, Safari, Firefox, Edge)
- Node.js (for development server)
# Clone the repository
git clone https://github.com/grimbixcode/mtgscan.git
cd mtgscan
# Install dependencies
npm install
# Start development server
npm run devOpen your browser to http://localhost:3000 (or the port shown in terminal).
Note: Camera access on mobile devices requires HTTPS in production. The dev server should handle this automatically. If not, you may have to generate certificate files by yourself.
- Start Camera: Tap "π· Kamera starten" to begin
- Position Card: Align card within the red frame guide
- Focus on Collector Number: Ensure the collector number (bottom-left) is in the yellow highlighted area
- Capture: Tap "πΈ Karte scannen"
- Review & Add: Verify the recognized card and add to your collection
Don't have a card handy? Use "π Bild hochladen" to test with existing card photos.
mtgscan/
βββ index.html # Main HTML structure with modal support
βββ src/
β βββ main.js # Core application logic (MTGScanner class)
βββ public/
β βββ style.css # Responsive styling with foil effects
β βββ privacy.html # Privacy policy (German)
β βββ terms.html # Terms of use (German)
β βββ imprint.html # Legal imprint (German)
β βββ legal-en.html # Legal summary (English)
βββ assets/
β βββ default-card.png # Placeholder card image
βββ sandbox/ # Advanced OCR testing framework
β βββ OCR-TESTING.md # Comprehensive testing guide
β βββ OCR_ANALYSIS_SUMMARY.md # OCR analysis results and recommendations
β βββ test-ocr.js # Basic OCR testing (11 configurations)
β βββ test-ocr-advanced.js # Advanced testing with preprocessing
β βββ fetch-card-names.js # Automatic card name fetching from Scryfall
β βββ card-mapping.js # Card code to name mapping system
β βββ test-images/ # Curated test image collections
βββ .github/
β βββ FUNDING.yml # GitHub Sponsors configuration
βββ Dockerfile # Production containerization
βββ ProductionDockerDeploymentGuide.md # Docker deployment instructions
βββ vite.config.js # Vite configuration with HTTPS support
βββ package.json # Dependencies and npm scripts
βββ WARP.md # Comprehensive development guide
- Single Class Design: Everything contained in
MTGScannerclass (~2,200 lines of focused functionality) - Event-Driven Flow: Clean separation between UI events, OCR processing, and data management
- Progressive Enhancement: Works without JavaScript for static legal pages
- Mobile-First Responsive: Optimized for phones with desktop compatibility
- Zero Server Dependencies: Everything runs client-side for privacy and simplicity
- Modular OCR Pipeline: Multiple fallback strategies for robust text recognition
- CSS in public/:
style.cssis in thepublic/directory to ensure both the main app and static legal pages can reference it correctly in production builds - Static Legal Pages: Privacy policy, terms, and imprint are static HTML files that don't require build processing
- Vite Build Handling: The main app's CSS gets bundled and optimized, while public files are copied as-is
- Full Resolution Capture: High-quality image acquisition from camera or upload
- Intelligent Card Detection: Smart cropping based on aspect ratio analysis
- Collector Number Region Extraction: Multiple cropping strategies (optimal, wider, offset)
- Foil Card Detection: AI-powered image analysis using color variance and brightness patterns
- Adaptive Image Processing:
- Normal Cards: Standard high-contrast enhancement with 2.5x factor
- Foil Cards: Specialized processing with dynamic thresholding and sigmoid smoothing
- Multi-Attempt OCR: Fallback system with confidence scoring
- Language-Agnostic Parsing: Supports all international MTG sets and language codes
- Exact Scryfall Integration: Direct API calls with language parameter support
Intelligent Foil Detection:
detectFoilCard(imageStats) {
// Foil cards have higher color variance and different brightness patterns
const foilIndicators = {
highColorVariance: imageStats.colorVariance > 15,
highMidtoneRatio: imageStats.midtonePixelRatio > 0.4,
lowerContrast: imageStats.darkPixelRatio < 0.3 && imageStats.brightPixelRatio < 0.3
};
// Foil detected if 2+ indicators present
return Object.values(foilIndicators).filter(Boolean).length >= 2;
}Adaptive Image Processing:
processCollectorNumberImage(canvas) {
const imageStats = this.analyzeImageCharacteristics(imageData.data);
const isFoil = this.detectFoilCard(imageStats);
if (isFoil) {
this.processFoilCollectorNumber(data, imageStats); // Dynamic thresholding
} else {
this.processNormalCollectorNumber(data); // Standard enhancement
}
}Multi-Collection Architecture:
// Collections metadata (localStorage: 'mtg-collections-meta')
{
"collections": {
"coll_timestamp_randomid": {
"id": "coll_timestamp_randomid",
"name": "Standard Deck",
"createdAt": "2024-12-23T20:00:00Z",
"cardCount": 60
}
},
"activeCollection": "coll_timestamp_randomid"
}Smart OCR Fallback System:
async performCollectorNumberOCRWithFallback(canvas) {
const strategies = [
{ name: 'optimal', cropFunc: () => this.cropToCollectorNumberArea(canvas) },
{ name: 'wider', cropFunc: () => this.cropToCollectorNumberAreaWider(canvas) },
{ name: 'offsetRight', cropFunc: () => this.cropToCollectorNumberAreaOffset(canvas) }
];
let bestResult = { text: '', score: 0, strategy: 'none' };
for (const strategy of strategies) {
const result = await this.performCollectorNumberOCR(strategy.cropFunc());
const score = this.scoreCollectorNumberResult(result.cleanedText);
if (score > bestResult.score) bestResult = { text: result.cleanedText, score, strategy: strategy.name };
if (score >= 80) break; // High confidence, use immediately
}
return bestResult.text;
}- One file, one responsibility
- Essential features only
- No complex frameworks
- Vanilla JavaScript with minimal dependencies
- β Complex CLAHE histogram equalization
- β Multiple region extraction strategies
- β Name-based OCR with language detection
- β Fuzzy card name matching
- β Multi-language support complexity
- β Advanced noise reduction algorithms
- β Clean, modern UI
- β Optimized collector number processing
- β Exact Scryfall API integration
- β Local storage collection
- β Progress feedback
- β Error handling
# Development & Build
npm run dev # Start Vite development server with HTTPS
npm run build # Build optimized production bundle
npm run preview # Preview production build locally
npm run serve # Simple Python HTTP server (fallback)
# πΊοΈ Advanced OCR Testing Framework
npm run fetch-cards # Auto-fetch card names from Scryfall API
npm run test-ocr # Run basic OCR tests (11 configurations)
npm run test-ocr:help # Show OCR testing help and options
npm run test-ocr:advanced # Advanced OCR with image preprocessing
npm run test-ocr:advanced:help # Advanced OCR testing help- Chrome (recommended)
- Safari (iOS/macOS)
- Firefox
- Edge
- Mobile browsers with WebRTC support
- Tesseract.js loads ~2MB on first OCR (English model only)
- Images processed client-side only
- Collection stored in localStorage
- Network calls only for Scryfall API lookups
Option 1: Static Hosting (Recommended)
- Netlify - Best for automatic deployments
- Vercel - Excellent performance and DX
- GitHub Pages - Free for public repos
Option 2: Docker Container
- Full production Docker setup available
- NGINX-based with optimized serving
- See
ProductionDockerDeploymentGuide.mdfor complete instructions
# Standard build for static hosting
npm run build
# Docker build for containerized deployment
docker buildx build --platform linux/amd64 -t mtgscan:prod --load .index.html- Main app with bundled and optimized CSS/JSstyle.css- Shared stylesheet for legal pages (copied from public/)privacy.html,terms.html,imprint.html,legal-en.html- Static legal pagesassets/- Optimized and hashed assets (images, bundled code)- Vite Optimizations: Separate Tesseract.js chunk, source maps, manual chunking
Contributions are welcome! This project follows the simplicity first principle.
Ask yourself:
- Is this essential for the core use case?
- Does this add complexity without significant benefit?
- Can this be implemented simply?
- Will users actually use this?
- ES6+ Classes
- Async/Await for async operations
- Try-catch error handling
- No global state (contained in class)
- π Bug fixes
- π± Mobile UX improvements
- π¨ UI/UX enhancements
- π Documentation improvements
- π§ Build process optimization
- Multi-Collection System: Create, manage, and switch between unlimited collections
- Intelligent Foil Detection: AI-powered analysis to distinguish foil from normal cards
- Advanced OCR Testing Framework: 23 configurations tested with comprehensive analysis
- Smart Fallback OCR: Multi-strategy recognition with confidence scoring
- Language Detection: Automatic recognition of card language from collector numbers
- Visual Foil Effects: Modal UI with shimmer effects for foil cards
- Docker Production Setup: Complete containerization with NGINX
- Adjustable Frame Sizing: Customizable scanning area for different use cases
- Image Upload Support: Scan existing photos in addition to live camera
- Advanced Image Caching: Intelligent localStorage management with auto-cleanup
- Collection Migration: Seamless upgrade path preserving existing data
- Collection Import/Export: JSON format for backup and sharing
- Card Price Integration: Optional TCGPlayer/CardMarket pricing
- Collection Templates: Pre-defined setups for common deck types
- Batch Card Processing: Scan multiple cards in quick succession
- Collection Analytics: Detailed statistics and insights
- PWA Support: Install as mobile app with offline capabilities
- Complex real-time video processing (performance/battery impact)
- Server-side infrastructure (maintains privacy and simplicity)
- User authentication (keeps it local and private)
- Database integrations (localStorage is sufficient and fast)
- AI-powered card name recognition (collector numbers are more reliable)
MTG Scanner is an unofficial fan project created by the community for the community.
- No Official Affiliation: This app has no connection to, endorsement by, or affiliation with Wizards of the Coast LLC, Hasbro Inc., or their subsidiaries
- Trademark Notice: Magic: The Gathering is a registered trademark of Wizards of the Coast LLC
- Card Data: All card images and information are provided via the Scryfall API and are subject to respective copyrights
- Fan Use Only: This project is intended for personal, non-commercial use by MTG players and collectors
- No Warranty: The app is provided "as-is" without warranties of any kind
- Local Processing: All images are processed locally on your device - nothing is uploaded to external servers
- No Tracking: No cookies, analytics, or user tracking
- Collection Storage: Your card collection is stored locally in your browser only
- API Requests: Only collector numbers (e.g., "FDN U 0125") are sent to Scryfall's public API
- OCR accuracy depends on lighting conditions and card quality
- Some older or damaged cards may not scan reliably
- Requires modern browser with camera support
- Collection data is tied to your browser/device
For detailed legal information, see the legal pages included with the app.
This project is licensed under the MIT License - see the LICENSE file for details.
- Scryfall API - Comprehensive MTG card database and the backbone of card identification
- Tesseract.js - Client-side OCR engine enabling offline text recognition
- Vite - Lightning-fast development builds and optimized production bundles
- Vanilla JavaScript - Keeping it simple, fast, and dependency-light
- OCR Analysis: Systematic testing of 23+ configurations to identify optimal settings
- Foil Detection Research: Image analysis techniques for distinguishing card finishes
- Mobile UX Studies: Real-world testing on various devices and lighting conditions
- MTG Community - Feedback, feature requests, and real-world testing
- Open Source Contributors - Bug reports and suggestions
- Magic: The Gathering - The incredible game that made this project worth building
- MDN Web Docs - Comprehensive WebRTC and Canvas API documentation
- Can I Use - Browser compatibility research for modern web APIs
- Privacy-First Design - No tracking, no servers, no data collection
- OCR accuracy depends on lighting and card condition
- Some older/damaged cards may not scan reliably
- Flash feature availability varies by device
- GitHub Issues - Report bugs and request features
- Discussions - Ask questions and share experiences
- Before posting: Check existing issues and search discussions
- README.md - Complete feature overview (you're reading it!)
- WARP.md - Comprehensive development and architecture guide
- ProductionDockerDeploymentGuide.md - Docker deployment instructions
- sandbox/OCR-TESTING.md - Advanced OCR testing framework guide
- sandbox/OCR_ANALYSIS_SUMMARY.md - OCR performance analysis and recommendations
- GitHub Sponsors - Support development and maintenance
- β Star the repo - Help others discover MTG Scanner
- Share your collection exports - Help test compatibility with other tools
- Contribute code - PRs welcome following the simplicity-first principle
- Be respectful - We're all here to enjoy MTG and technology
- Follow simplicity principle - Feature requests should enhance core functionality
- Provide context - When reporting issues, include device, browser, and steps to reproduce
- Test thoroughly - Use the OCR testing framework when contributing OCR improvements
"Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away." - Antoine de Saint-ExupΓ©ry
β Star this project if it helps with your MTG collection!