Random problem trainer for AMC 8, AMC 10, AMC 12, and AIME math competitions.
Frontend: SvelteKit static site (adapter-static) deployed to GitHub Pages from main branch. Pushes go live immediately.
Backend: Cloudflare Worker (worker/) with D1 (SQLite) database. REST API serving problems, solutions, and answers.
Data Ingestion: Python scraper (worker/scraper.py) fetches problems from the AoPS wiki, parses HTML, extracts answers, and POSTs batches to the worker's /api/problems/ingest endpoint (API-key protected).
src/
lib/
components/ # Svelte 5 components (runes: $state, $derived, $effect, $props)
stores/ # Svelte writable stores (settings, problem, streak, stats)
services/ # API client (aopsClient.ts), answer validation
types/ # TypeScript interfaces and type aliases
routes/
+page.svelte # Landing page
play/ # Main trainer page
+layout.svelte # App shell (background gradient, CSS vars)
app.css # Global styles
worker/
src/worker.ts # Cloudflare Worker API
scraper.py # Python ingestion script
wrangler.toml # Worker config
static/img/ # SVG icons and logo variants
- User clicks Next ->
loadNewProblem()instores/problem.ts - Calls
fetchRandomProblem()inservices/aopsClient.ts - Hits
GET /api/problem/random?level=...&subject=...on the CF Worker - Worker queries D1, returns JSON with problem HTML, solution HTML, answer
- Frontend renders HTML directly, runs KaTeX for LaTeX, proxies AoPS images
- Package manager: bun (not npm)
- Framework: Svelte 5 with runes ($state, $props, $derived, $effect)
- Styling: Global CSS in app.css, scoped CSS in components
- Settings: All user preferences stored in localStorage via
stores/settings.ts - CSS variables:
--bg-color-1,--bg-color-2,--text-color,--text-invertset on the app div in +layout.svelte - Deploy:
git pushto main triggers GitHub Pages build
GET /api/problem/random?level=&subject=&difficulty_min=&difficulty_max=- Random problemGET /api/problem/:id- Specific problem by IDGET /api/stats- Problem count by exam and subjectPOST /api/problems/ingest- Bulk upsert (API-key required)GET /api/image-proxy?<url>- CORS proxy for AoPS images (restricted to AoPS domains)