-
-
Landing page (All the topics)
-
Topic explorer
-
visualiser slide 1
-
visualiser slide 2
-
visualiser slide 3
-
visualiser slide 4
-
test generator
-
generated 4mcq test
-
Knowledge arcade
-
game 1 (wordle)
-
game 2 (spelling bee)
-
game 3 (crossword)
-
game 4 (sprangle)
-
coupon tradecenter
-
profile (overall progress analysis)
Shooting Star
Inspiration
I failed a chemistry test once and the entire feedback was a number: 62%.
Sixty-two percent of what, though? I didn't know whether I'd misunderstood bonding, or whether I actually understood everything fine and just kept fumbling reaction rates. So I did what everyone does: reread the whole chapter, learned nothing new, and stayed exactly as weak in exactly the same place.
That's the gap I wanted to close. Not "here's your score," but "here is the specific idea that broke, and here is that idea, animated, until it stops being confusing."
The second half of the idea came from watching how differently I treat things that pay me back. I'd skip revision without a second thought, but I'd never skip something with a streak or a reward attached. Study apps are quietly terrible at retention because there's no reason to open them tomorrow. So I gave Shooting Star one: you earn points as you learn, and you spend them on real coupons from brands you'd buy from anyway.
What it does
Your subjects become a 3D constellation. Each topic is a star; click one and you fly into its solar system, where the subtopics orbit as planets, lit according to how well you actually know them.
- Create a topic. Type a subject, or upload a syllabus PDF. The backend uses a web search to ground itself, then generates the subtopic breakdown.
- Take a test. MCQs, long-form answers, or flashcards, timed if you want the pressure.
- Get diagnosed, not graded. Answers are analysed per subtopic, so the result is "bonding is solid, you're losing marks on reaction rates," not a percentage.
- Watch the concept get built. The weak subtopic is turned into a narrated Video Overview: animated mind maps, flowcharts, step-by-step algorithm animations, and scene diagrams that move while a voice walks you through them.
- Retake it and watch the planet light up.
- Spend what you earned in the Trade Center on real, verified coupon codes, or on cashback scratchcards.
There's also an Arcade that generates Wordle, Spelling Bee, crossword, and Strands puzzles (Inspired by our own NYT games) from your own topic vocabulary, so the revision loop has a low-effort entry point on days when a full test feels like too much.
Mastery is a moving average, not a snapshot
A single test shouldn't define a planet. After each attempt, per-subtopic mastery blends the old value with the new accuracy:
$$m_{\text{new}} = \operatorname{round}\left(0.6\,m_{\text{old}} + 0.4\,a\right)$$
where $a$ is your accuracy on that subtopic in the latest attempt. One bad day doesn't wipe a planet dark, and one lucky guess doesn't light it up. You have to be consistently good before the sky agrees with you.
How I built it
Frontend: React + TypeScript + Vite, with react-three-fiber and drei over three.js for the constellation and solar system. The concept visualiser renders slides as SVG/canvas animations, and the narration runs on the browser's built-in speechSynthesis API, which means the "Video Overview" costs nothing per play and needs no API key.
Backend: FastAPI + SQLAlchemy 2.0 + Pydantic v2, on Supabase Postgres. It owns auth (JWT), topics, attempts, grading, per-subtopic analysis, concept generation, and the arcade.
LLM layer: Ollama Cloud running gpt-oss:20b, called through a single adapter with JSON mode enabled. Every call site goes through one complete_json() function that validates and repairs the response, and there's a deterministic MockProvider that takes over automatically whenever the model is unreachable. The app never hard-fails because an LLM had a bad moment.
Coupon service: a second FastAPI service that owns the rewards catalogue. It's deliberately separate: a scraper populates codes on a schedule, and the request path only ever reads pre-validated data. It never scrapes while a user is waiting. Both services share one Postgres database and one JWT secret, so a single login works across both.
Deployment: one Vercel project serving the Vite build as static output and both FastAPI apps from a single Python serverless function behind the same domain, so production has no CORS surface at all.
Challenges I ran into
Getting reliable JSON out of a small model. This ate the most time by far. A 20B model asked for a structured quiz will cheerfully hand you an MCQ where two options are the same word, or JSON that's truncated mid-array because it hit the token cap. I ended up raising max_tokens, capping reasoning effort so structured calls stayed fast, and, most importantly, adding validation with a bounded regeneration loop: reject the malformed set, ask again, and after N failures fall through to the mock provider rather than showing the user a broken test. Bounded is the key word there. An unbounded retry loop against a slow model is just a hang with extra steps.
Diagram layout is a real geometry problem. Mind map children clipped their own text, and flow nodes overlapped as soon as a concept had more than a handful of steps. Fixed sizing doesn't survive arbitrary AI-generated labels, so node dimensions and spacing had to be computed from the actual content at render time.
Moving from SQLite to Postgres broke things quietly. Most obviously, generated subtopic IDs were longer than the column allowed: fine on SQLite, a hard error on Postgres.
Concurrent redemption. Two users spending points on the last copy of a coupon code at the same time cannot both get it. The redeem path uses SELECT ... FOR UPDATE row locking on Postgres, and the points ledger is append-only, so a balance is never edited in place, only derived from summed deltas.
Deploying a two-service Python stack to serverless was its own project. Four things went wrong in sequence, and each one looked like the previous fix hadn't worked:
- Vercel auto-detected the project as a FastAPI backend, which silently stopped it serving the frontend build at all. Every page load 404'd through the API function. The fix was forcing the framework to "Other."
- Rewrites forward the destination path to the function, not the path the browser asked for, so every route arrived as
/api/indexand FastAPI 404'd on all of them. The original path now travels in a query parameter and gets restored by ASGI middleware before routing happens. prepare_threshold=0in the database URL crashed every single query with aTypeError, because URL parameters arrive as strings and psycopg compares that value numerically. It also turns out that0doesn't disable prepared statements in psycopg 3 (Nonedoes), and the Supabase transaction pooler can't support them at all.- Serverless functions needed connection pooling turned off, since every cold-started instance holding its own idle pool adds up fast against the database's connection cap.
What I learned
- Design for the model being wrong. The single best decision in this project was the mock fallback provider. Every feature works offline with deterministic output, which meant a flaky model never blocked frontend work, and it means the demo can't die on stage.
- "It works locally" and "it works on serverless" are different claims. Long-lived connection pools, lifespan hooks, and prepared statements are all things a normal server does happily and a serverless function punishes you for.
- Read the platform's warnings. Vercel logged a one-line notice about rewrite path semantics changing. I skimmed past it, then spent a long time reverse-engineering the exact behaviour it had just described.
- Boring diagnostics beat clever guessing. I got nowhere theorising about the 404s. Deploying a probe endpoint that simply reported the path and headers the function actually received ended the guesswork immediately.
- Feedback specificity is the whole product. "You're losing marks on reaction rates" does more for a student than any amount of 3D polish. The galaxy makes people open the app; the diagnosis makes it worth opening.
What's next
- Spaced repetition: resurface a planet right as its mastery is about to decay.
- Shared constellations, so a class can see which subtopics the whole group is weak on.
- Moving quiz generation off the request path into a background job, so slower, better models become an option.
- Expanding the scraper's sources and tightening code verification before anything reaches the catalogue.
Built With
- beautifulsoup4
- duckduckgo
- fastapi
- gpt-oss
- httpx
- javascript
- jwt
- ollama
- postgresql
- psycopg
- pydantic
- pypdf
- python
- react
- react-router
- react-three-fiber
- recharts
- sqlalchemy
- supabase
- three.js
- typescript
- uvicorn
- vercel
- vite
- web-speech-api
Log in or sign up for Devpost to join the conversation.