A fantasy-themed SQL learning game built with Next.js 14. Players solve mysteries across magical locations by writing real SQL queries against in-browser SQLite databases. Teachers can create custom quests and track student progress through a dedicated dashboard.
- Guest mode — play fully offline, no account required; progress saved to localStorage
- 5 built-in locations — each with themed SQLite databases and multi-step mystery quests
- In-browser SQL engine — powered by sql.js (SQLite compiled to WASM); no server needed
- NPC dialogue with typewriter effect and skip support
- Hint system with escalating clue tiers
- Achievement engine — auto-awarded based on play behavior
- Case Solved overlay with animated summary
- Procedural sound effects via Web Audio API
- Auth and cloud sync (optional) — Supabase auth, per-quest progress synced to cloud
- Teacher dashboard — live roster with quest completion stats and efficiency metrics
- Quest Forge — teachers design custom quests with DDL/DML, compiled to
.sqlitein-browser, uploaded to Supabase Storage - Notice Board — students enter a quest code to load and play teacher-created quests
- Row Level Security — Supabase RLS policies enforce data isolation between students and teachers
| Layer | Technology |
|---|---|
| Framework | Next.js 14 (App Router, TypeScript) |
| SQL Engine | sql.js (SQLite WASM) |
| DB Build | better-sqlite3 (build-time only) |
| State | Zustand + persist middleware |
| Code Editor | CodeMirror 6 via @uiw/react-codemirror |
| Animations | Framer Motion |
| Sound | Web Audio API (procedural, no assets) |
| Styling | Tailwind CSS |
| Backend | Supabase (auth, Postgres, Storage) |
| Auth middleware | @supabase/auth-helpers-nextjs |
- Node.js 18+
- npm or pnpm
git clone <repo-url>
cd sql-quest
npm installThe built-in location databases are compiled from seed scripts at build time. Run this once after cloning:
npm run build:dbThis writes .sqlite files to public/databases/. The script uses better-sqlite3 (Node.js only) and is not shipped to the browser.
Copy .env.example to .env.local and fill in your values:
cp .env.example .env.localWithout Supabase configured the game runs entirely in guest mode (100% offline, localStorage only). Auth, cloud sync, and teacher features require a Supabase project.
npm run devOpen http://localhost:3000.
- Create a project at supabase.com.
- Copy Project URL and anon public key into
.env.local. - In the Supabase SQL Editor, run the full migration:
This creates all tables, enables Row Level Security, and sets up the
supabase/migrations/20260306_rls_policies.sqlcustom_databasesStorage bucket. - Verify the
custom_databasesbucket exists under Storage in your Supabase dashboard.
| Table | Purpose |
|---|---|
profiles |
User profile — username, role (student / teacher), class membership |
quest_progress |
Per-user quest state — attempts, hints used, completion time, last query |
user_achievements |
Earned achievement IDs per user |
classes |
Teacher-owned classes with invite codes |
custom_quests |
Teacher-authored quests — narrative, expected SQL, link to custom .sqlite |
src/
app/
page.tsx # Home / world map
play/
[locationId]/ # Built-in location lobby
[buildingId]/ # Quest interior + SQL terminal
custom/[questId]/ # Custom quest player
archmage-tower/
apprentices/ # Teacher roster page
forge/ # Quest Forge (5-step form)
auth/login/ # Auth page
components/
game/ # NPCDialogue, CaseFile, HintSystem, CaseSolved, WorldMap, ...
ui/ # MagicalButton, shared primitives
hooks/
useAuth.ts # Supabase auth state
useCustomSQLEngine.ts # Loads remote .sqlite, runs expected SQL
useSQLEngine.ts # Built-in location SQL execution
useGameStore.ts # Zustand store (progress, achievements, sync)
lib/
sql-engine.ts # sql.js wrapper, DB cache, loadDatabaseFromUrl
supabase.ts # Typed Supabase client + all DB helpers
achievements.ts # Achievement definitions and evaluator
quests/ # Quest data for each location
middleware.ts # Teacher-only route guard for /archmage-tower
scripts/
build-databases.ts # Generates public/databases/*.sqlite at build time
supabase/
migrations/
20260306_rls_policies.sql # Full RLS + Storage bucket setup
| Script | Description |
|---|---|
npm run dev |
Start development server |
npm run build |
Production build |
npm run build:db |
Compile SQLite databases from seed scripts |
npm run lint |
ESLint check |
- Teacher opens the Quest Forge (
/archmage-tower/forge) and completes the 5-step form:- Quest metadata (title, location, difficulty)
- Narrative / case description
- Expected SQL answer
- DDL + seed data SQL
- Review and publish
- The DDL runs in an in-browser sql.js instance. The resulting database is exported as a binary and uploaded to Supabase Storage.
- The quest record (including the public database URL) is saved to the
custom_queststable. - Students click the Notice Board on the world map, enter the quest code, and are routed to
/play/custom/[questId]. - The custom quest player fetches the remote
.sqlite, executes the teacher'sexpectedSqlto derive the correct result set, then validates student submissions against it.
- Run
npm run build:dbto generate SQLite files. - Run
npm run buildto verify a clean production build. - Apply
supabase/migrations/20260306_rls_policies.sqlin your production Supabase project. - Set
NEXT_PUBLIC_SUPABASE_URLandNEXT_PUBLIC_SUPABASE_ANON_KEYin your hosting environment. - Deploy — the app is compatible with Vercel, Netlify, and any Node.js host.