Netdecker / Mana Pool Project
Overview
Built netdecker.app as a job application project for Mana Pool (manapool.com). Scrapes top Standard decklists from major paper tournaments, resolves card names via Scryfall, and optimizes pricing through the Mana Pool buyer/optimizer API.
Live: netdecker.app Source: github.com/ptaranat/netdecker Stack: SvelteKit, Bun, Cheerio, SSE streaming, deployed on Railway
Key Learnings
mtgdecks.net scraping
- Cloudflare blocks Bun/Node fetch (TLS fingerprinting), only curl works locally
- Dates on archetype pages are client-rendered, not in HTML
- Sort by Event.relevance/direction:desc for best tournament results
- Filter out W/L entries (no notable finish) and Japanese store events (HARERUYA, Kichijoji)
- Big star events (font-size:16px) = Regional Championships / major paper events
- Tournament page lists decks in placement order (1st, 2nd, Top4, etc.)
Mana Pool API
- Auth headers: X-ManaPool-Email, X-ManaPool-Access-Token (or email, access-token)
- POST /buyer/optimizer returns NDJSON (streaming), take 2nd line for near-optimal result
- 409 means cards not in inventory, retry after removing unavailable cards
- Optimizer can take 30-90 seconds for a full decklist
- POST /job-apply needs Origin: https://manapool.com header (SvelteKit CSRF)
Scryfall
- /cards/collection (batch up to 75) resolves DFC names and returns prices
- Fuzzy search fallback for OM1 renames (e.g. Kavaero → Superior Spider-Man)
- Rate limit: 50-100ms between requests, User-Agent required
- Image URL: /cards/named?exact=NAME&format=image&version=normal
- Back face: add &face=back
Card name issues
- mtgdecks uses front face only: Hearth Elemental (not Hearth Elemental // Stoke Genius)
- OM1/SPM renames: some cards have completely different names across sets
- Basic lands: showed Kamigawa Neon Dynasty full art Japanese as easter egg (NEO 293-302)
Mana Pool Job Details
- Senior/Principal Software Engineer, founding team (2nd engineer)
- Stack: TypeScript, Svelte, PostgreSQL, Supabase
- $135k-200k + equity
- Application submitted via POST /job-apply on 2026-03-14