( Independent Practice / 2026 )
TCG Card Recognizer
Delivered a working card recognizer to the Girudo team, unblocking a capability their own attempt had stalled on, built and handed over as an independent project alongside the platform design engagement
- My role
- Freelance UI/UX Designer
- Timeline
- 2026
- Category
- Computer Vision / OCR / Trading Card Games
- Status
- New design, delivered
Tools Claude Code, Python, Flask, OpenCV, PyTorch, ONNX Runtime, Apple Vision, RapidOCR, Tesseract, Google Gemini, React 19, Vite, TypeScript
Generated schematic, not a screenshot. Real imagery to follow.
( The account )
Context
Trading card play has moved onto camera. Players stream their games, play remotely against a webcam pointed at the table, and increasingly expect the software watching that table to understand the game rather than just relay it. The reference point for that behaviour is SpellTable, where clicking a card in a video feed tells you which card it is.
Girudo is a trading card game community and creator platform I had already designed end to end as a separate engagement. Its team had been trying to build the card recognition the platform depends on and had run into an accuracy wall they could not get past. I took it on as an independent project, built it separately from the platform design work, and delivered the working system to them.
The build targets Magic: The Gathering first, with the full catalog of 27,663 cards carrying complete visual signatures, and the interface prepared for four further games behind the same pipeline.
The problem
Girudo's premise is that people play with their actual physical cards online, streaming their table to opponents and spectators. That premise only holds if the software knows what is on the table. A camera feed of a card game is just video, and video is what Twitch already does better than a startup can. The thing incumbents structurally cannot offer is hosting the game itself, and hosting the game starts with recognising the cards in it. Recognition was not one feature among the platform's modules. It was the capability that the differentiating half of the product rested on.
Everything downstream needs the same question answered first: which card is that. A spectator following a match cannot read a card held up to a webcam across a room, so the card played has to be identified on screen for the viewing experience to work at all. An opponent playing remotely needs the same thing to make a decision without asking someone to hold a card closer to the lens. Decklists and state tracking need to know what entered play. Without recognition, every one of those becomes manual typing, and a player who has to stop and type is a player who goes back to Discord and a webcam. The feature that justifies the platform quietly becomes the feature nobody uses.
That need had gone unmet because the problem is much harder than it looks from outside. Reading text from an image is solved; reading a trading card on a table is not the same problem. Foils throw glare across the exact band the title sits in. Borderless and showcase printings move or remove the title band entirely. Cards on a real table are angled, partially shadowed, and lit by whatever lamp is in the room. Older frames use type treatments no modern OCR model was trained on. Every one of these is normal rather than exceptional, and each degrades the single signal the obvious approach depends on.
The second constraint only appears at scale, and it is the one that decides whether the feature is usable. When the reference catalog holds tens of thousands of cards, a weak reading does not fail visibly. It produces a confident wrong answer, because somewhere among 27,663 candidates something always plausibly matches a bad read. A system that names the wrong card is worse than no system, because a player who cannot trust it has to verify every result by hand, at which point the tool costs more attention than it saves. That is where the effort had stalled: not at getting it working on clean cards, but at getting it trustworthy enough that a player would leave it switched on.
What I did
The core move is to stop treating this as an OCR problem. Instead of one signal read well, the recognizer reads four independent signals and fuses them: OCR on the title band, a 256-bit perceptual hash of the artwork window verified by normalised cross-correlation against stored thumbnails, ORB keypoints with RANSAC homography verification, and a coarse colour and region feature vector. Each runs across four orientations, so a rotated or upside-down card costs nothing. A whole-card OCR rescue pass handles borderless and showcase frames that have no standard title band to read.
The signals fail in different ways, which is the point. Glare that ruins the title band leaves the artwork hash intact. A borderless frame with no title still has distinctive art and keypoints. Fusion scores agreement between signals higher than any single strong reading, and applies an explicit penalty to a result carried by one signal alone once the index grows past a few thousand cards, which is exactly the condition that produces confident wrong answers.
Underneath the fusion sits a stated principle: a wrong answer is far worse than no answer. The system carries a confidence floor and abstains below it, returning ranked candidates rather than a bare failure, so an uncertain read surfaces as a short list the player resolves in one click instead of a false certainty they have to catch themselves.
Above it sits an escalation tier. When the local pipeline is not confident, the click escalates to Google Gemini as a vision fallback with a structured output schema. Gemini's answer is then grounded against the local catalog by fuzzy name match and written back into the local index, so the same physical card matches locally and instantly on every future sighting. The system gets faster and cheaper the more it is used, and the cloud dependency shrinks with use rather than growing.
Outcomes
- Delivered a working card recognizer to the Girudo team, unblocking a capability their own attempt had stalled on, built and handed over as an independent project alongside the platform design engagement
- Built a recognition pipeline that fuses four independent signals across four orientations, so the failure modes that defeat OCR alone, foils, glare, angled cards, and borderless frames, are covered by signals that do not fail together
- Indexed the complete Magic: The Gathering catalog of 27,663 cards with full visual signature coverage, searchable as a vectorised bit-distance lookup rather than a scan
- Demonstrated a self-improving escalation model in which cloud vision handles only what the local pipeline cannot, and every escalated answer is written back so the same card resolves locally and instantly thereafter
- Kept the live camera loop entirely client-side at roughly 5 ms per frame, reducing a recognition to a single request carrying one crop, with indexed cards returning a verdict in 0.1 to 0.4 seconds
- Made the recognizer's reasoning observable through a live activity trace and ranked alternatives, so an uncertain result is legible to the player rather than presented as a false certainty
- Produced a reusable evaluation apparatus, a synthetic scene generator with lighting and glare simulation plus a benchmark harness that reports which signal carried each identification, so future changes can be measured rather than guessed at
What I learned
The accuracy wall was not where the team thought it was. They were trying to read cards better, and the answer was to stop depending on reading them at all. Reframing a recognition problem as a signal fusion problem rather than a text extraction problem is what unlocked it, and that reframing was worth more than any amount of tuning on the original approach. It is a reminder that when a technical effort stalls, the constraint is often in how the problem was framed rather than in the execution.
Designing for uncertainty is a product decision, not an engineering detail. The choice to abstain and offer candidates rather than assert a best guess shaped the confidence floor, the fusion penalty, the results panel, and the correction dialog, all of which exist because the system is allowed to be unsure. Building a product that admits doubt turned out to be what made it trustworthy enough to use.
Measurement changed the architecture more than intuition did. Testing under synthetic glare and low light, rather than on clean scans, is what revealed that crop precision matters more than crop convenience, and that keypoint matching stays discriminative exactly where perceptual hashing degrades. Neither was obvious in advance, and both moved real structure in the system. The open items are honest ones: two adjacent cards can still merge into a single detection, and the neural detector needs a retrain with hard negatives before it stops firing on hands and keyboards.
( Tags )
- Computer Vision
- OCR
- Image Recognition
- Perceptual Hashing
- Feature Matching
- Multi-Signal Fusion
- Machine Learning
- Neural Segmentation
- ONNX
- Full-Stack
- AI Product
- Claude Code
- Google Gemini
- Python
- Flask
- OpenCV
- PyTorch
- React
- TypeScript
- Trading Card Games
- Real-Time