Inspiration
What it does
How we built it
Challenges we ran into
Accomplishments that we're proud of
What we learned## Inspiration
Studying alone is brutal. Apps like Forest and Pomodoro timers help for 25 minutes, but then what? We wanted studying to feel like progress — not just a streak number, but a world you can see filling up. We mixed two ideas we love: the satisfying ink-spread of a strategy game + the tension of Alice in Borderland's sealed exam rooms. The result is Pseudopodia: your focus literally paints a living earth.
What it does
Pseudopodia is a free, browser-based Focus RPG.
- Focus to paint: Pick a run from 30 minutes to 12 hours. Stay focused and your ink spreads across a flat paper world and a real 3D globe. Leave fullscreen and you get eliminated.
- 24 unlockable inks: From Common
Zebra&Jadeto LegendaryKintsugi,Ember&Frost— each with a seamless SVG motif drawn withCanvasPattern. Tiles scale with zoom so they never look tiny. - Exam Rooms — the sealed acid room: Create or join a custom room with a 5-char code. You set the subject, class/page, source, question count (3-20) and seats (2-10). The AI writes a fresh paper just for that room. Everyone answers together — fastest correct answer takes the round, wrong/silent = 1 acid pixel. Light 10 and you're out. Last one standing wins. Coins by rank: 1st +50, 2nd +30, 3rd +20, 4th +10.
- Live, real points: You see every desk flip in real-time —
✓ 2.3s, who locked first, who got it right — and the center board updates instantly. - AI thinking, visible: No silent "Exam cancelled" anymore. A Flow-Morph 5-dot animation + live feed shows only sources & steps (
Reading NCERT Class 10 Science,Fetching diagrams from Wikimedia Commons...) — never the questions.
Focus time = Ink, Coins, Scholar XP, and Streaks. Abandoned runs still give up to 25% so effort is never wasted.
How we built it
No frameworks, no heavy deps — just the web platform done right.
- Frontend: Vanilla JS (classic scripts for deterministic load order),
Vitefor build,Three.jsonly for the globe. The globe is lazy-loaded viaglobe-loader.jsso the lobby is instant; vendor code is code-split. - 2D World:
<canvas>flat map with organic spread — frontier cells are picked uniformly at random, not sorted. Ink motifs are 128px SVG tiles applied asCanvasPatternwithDOMMatrixscaling so one motif = one cell at any zoom. - 3D Globe: Procedural Earth (fbm noise: oceans, forests, snow, ice caps) + drifting cloud layer. Falls back to procedural when offline, uses
LinearMipmapLinear+ max anisotropy for sharp continents. - AI Paper Pipeline:
Vercel Serverless /api/quizproxies to Qwen/GLM. System prompt demands Unicode math ((cos θ + i sin θ)^nnot^), classroom-safe content, and per-questionseconds(8-90s). Papers stream in batches (3 at a time) while you answer, deduped by question text.Wikimedia Commonsimages are allowlisted (upload.wikimedia.orgonly, png/jpeg/webp/gif) and capped to 8 per paper. - Safety: Blocklist (
ADULT_TERMS) checks topic before the model is called (400 topic_blocked) and drops any generated question that slips through. - Infra:
dist/is deployed to Vercel with History API fallback toindex.htmlfor/globe.sharp+pngjsgenerateog-image.png(1200x630) at build.
Challenges we ran into
- Blank arena on Play:
flatCanvas.style.display='none'while globe was visible maderesize()measure0x0→ bitmap clamped to1x1. Fixed withrequestAnimationFrame(resize)after flipping back to flat + aresizelistener. - Ink looked tiny when zoomed: Pattern was a fixed tile. Fixed by
pattern.setTransform(new DOMMatrix([k,0,0,k,0,0]))wherek = cellSize / 128. - Cold free-tier AI channel: ~40% fail rate when cold, 10-20s cooldown. Solved with batched streaming, single in-flight request per session, cooldown-aware retries, and an
OFFLINE PRACTICEfallback — but top-ups never inject fallback, the exam ends with dignity instead. - "Everyone wrong = no points":
beginExamRevealwas resettingphaseT=0before checkingbotLockAt— every bot answer was discarded. Now answers are snapshotted atstoppedAtbefore the reset. - Readable but not broken UI: An
!importantoverride for lobby readability was also killing.picked/.correct/.wronghighlights. Replaced with a scoped fix + a tick-checkbox (✔/✘) so selection is unmistakable in light/dark mode.
We verified everything headless with playwright-core + SwiftShader and npm run quality (lint + prettier + 104 tests + build + smoke).
What we learned
Shipping a real game on just HTML/CSS/Canvas taught us more than any framework: how CanvasPattern transforms work, how to make Three.js textures crisp at every zoom, and how to design around flaky LLMs (deadlines, retries, streaming) instead of pretending they're reliable.
What's next
Friends-list + voice in exam rooms, ink trading, and a teacher mode where a PDF becomes the source for the paper.
Built by students, for students. Your focus paints the world.
Built With
- html5
- javascript
- node.js
- qwen
- three.js
- vercel
- vercel-serverless-functions
- vite
- wikimedia-commons-api
Log in or sign up for Devpost to join the conversation.