This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady
What I Built
QuestSloth automates a chore teachers dread β turning dry syllabus notes into quizzes β and makes studying feel like a tiny dungeon crawl.
-
Teacher Forge β paste lecture notes. Open-weight Gemma 2 2B runs locally in the browser via WebLLM and emits a strict
quest.json(quest title, boss name, five MCQs, answers, explanations). - Student Dungeon β play that pack with no AI inference: HP bars, combos, difficulty modes, consumable powers, achievements, procedural SFX + battle music. Correct answers hurt the boss; misses hurt you and show the explanation.
Slow and steady / International Sloth Day: the teacher stops inventing five MCQs by hand; students get a boss fight instead of a worksheet. Notes never leave the device.
Demo
Live app: https://arjankc.github.io/QuestSloth/
-
Forge needs WebGPU (recent Chrome/Edge). First Gemma download is ~1.5GB for the f16 build (or ~2.5GB if your GPU lacks
shader-f16and Forge falls back to q4f32) and caches in the browser. - Dungeon works without loading any model β try Play sample quest immediately. Unmute the header speaker for lobby pad / battle BGM / SFX.
- Forge Play in Dungeon hands the pack over via
sessionStorage(plus a short local quest stash).
Code
Repo: https://github.com/arjankc/QuestSloth
arjankc
/
QuestSloth
Browser-local Gemma turns lecture notes into dungeon quizzes (Hacktoberfest 2026 Week 3)
QuestSloth
Turn lecture notes into a dungeon-crawler quiz β entirely in the browser.
Built for Hacktoberfest Open-Source AI Challenge: Week 3 β Slow and Steady. Teachers paste notes; local Gemma 2 2B (via WebLLM) forges a quest.json. Students fight the boss by answering β no inference on the play path.
Why open weights?
- Notes never leave the device (Forge runs on-device WebGPU).
- No OpenAI/Claude bill for every quiz.
- Students only need the JSON file β the dreaded βwrite five MCQs by handβ chore becomes a paste β download.
Stack
- Vite + React + TypeScript + Tailwind CSS
-
@mlc-ai/web-llmΒ· prefersgemma-2-2b-it-q4f16_1-MLC-1k(~1.5GB); auto-falls back togemma-2-2b-it-q4f32_1-MLC(~2.5GB) when WebGPUshader-f16is missing - Static host: GitHub Pages (
base: '/QuestSloth/', HashRouter)
Modes
| Mode | Route | AI? |
|---|---|---|
| Teacher Forge | #/forge |
Yes β loads Gemma, emits strict quest JSON |
| Student Dungeon | #/dungeon |
No β upload JSON, forged handoff, sample, or |
Worth a look:
-
src/lib/webllm.tsβ Gemma load + f16 feature probe + q4f32 fallback + low-temperature JSON generation -
src/lib/questSchema.tsβ Zod validation + JSON Schema for constrained decoding -
src/lib/difficulty.ts/src/lib/powers.ts/src/lib/progress.tsβ Easy/Normal/Hard, Hint/Shield/Focus, XP + achievements -
src/lib/audio.tsβ procedural Web Audio (no sound files) -
src/pages/Forge.tsx/src/pages/Dungeon.tsxβ the two halves of the product
How I Built It
Constraints drove the stack: ~30GB free disk, 4GB VRAM, no Python/Ollama/Docker. Everything is a static SPA on GitHub Pages.
flowchart LR
notes[LectureNotes] --> forge[TeacherForge]
forge --> webllm[WebLLM]
webllm --> gemma[Gemma2_2B]
gemma --> pack[quest.json]
pack --> dungeon[StudentDungeon]
dungeon --> fight[BossFight]
-
Vite + React + Tailwind for routing and game state (
HashRouter,base: '/QuestSloth/') -
@mlc-ai/web-llmprefersgemma-2-2b-it-q4f16_1-MLC-1k(~1583MB VRAM). On GPUs that don't advertise WebGPUshader-f16, Forge probesadapter.featuresand loadsgemma-2-2b-it-q4f32_1-MLCinstead (~2.5GB) β same Gemma 2 2B IT weights, no Canary flags required. If the probe misses, a create failure matchingshader-f16triggers one automatic retry. -
Strict JSON:
temperature: 0.15, WebLLMresponse_format: { type: "json_object", schema }, then Zod parse + one repair retry - Code-split Forge so the Dungeon route never pulls WebLLM (phone-friendly play)
- Game loop: difficulty tables, one-power loadout (Shield/Focus unlock at level 2), combos, level combat bonuses, achievements, CSS battle FX, lobby pad + battle BGM that speeds up on enrage
Small models love to ignore free-form prompts. Constrained decoding plus a validator kept the dungeon from crashing on bad packs β the same lesson browser-Gemma builders keep rediscovering (Touch Soil is a good peer example of schema-shaped WebLLM output).
The f16 fallback was a live-demo fix: WebLLM's f16-1k build hard-requires shader-f16, and shipping only that ID meant some Chrome/Edge users (especially integrated GPUs) got a Canary flag error instead of a quiz. Probe + q4f32 keeps Best Use of Gemma reachable on more hardware β the same pattern in-browser LLM posts keep hitting (WebGPU present β WebGPU usable; ship a quantization per backend).
Why Does Open Innovation Matter?
- Classroom notes stay on the laptop. Forge never posts syllabus text to a paid API.
- Zero inference bill after the one-time model cache β important if you forge quizzes every week.
- Students only need the JSON file. Schools with locked-down or low-end devices can still play the dungeon.
-
Swappable brain. The model id is one string in
webllm.ts; any WebLLM Gemma (or other open weight) can replace it.
Lazy payoff: paste notes β download (or hand off) quest β share with the class. The chore of inventing five decent MCQs disappears.
Prize Categories
- Best Use of Gemma β Teacher Forge runs open-weight Gemma 2 2B in-browser via WebLLM to generate every quest pack.
Top comments (0)