Dr. Claw
Full-stack research workspace. From idea to paper with AI agents.
A prototype with two learning modules: a textbook tutor that writes source-cited quizzes, and an audio-first letter tracing studio for English and Hindi.
EducationTypeScript · CSSGitHub @Pranav-d33OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗A working prototype with two learning modules behind one entry point:
| Module | For | What it does |
|---|---|---|
Textbook AI Tutor (/tutor) | Teachers, tutors, Classes 1–10 (demo: Class 1 English) | Upload a textbook PDF (or use the built-in demo reader), choose question types / count / difficulty / scope, generate source-grounded questions, review and edit them with page citations, run the quiz, and score it. |
Early Learning Studio (/early) | LKG–UKG children with an adult nearby | English A–Z and a curated Hindi set. Hear each letter and its picture words, then trace it with finger, stylus or mouse and get gentle spoken feedback. |
No accounts. Works fully without an API key in a clearly labelled demo mode; add a key to switch question writing and open-answer grading to a live model.
The earlier static design mockup is preserved unchanged in
../opendesign/. This app replaces it with a real implementation and reuses its design direction, letter data and demo passages.
Requirements: Node.js ≥ 20.9 (tested on 24), npm.
npm install
npm run dev # http://localhost:3000
That's it — demo mode works immediately. To enable live AI mode:
cp .env.example .env.local
# then set ONE of these in .env.local:
# LLM_API_KEY=AIza... (Google Gemini — also enables embeddings)
# LLM_API_KEY=gsk_... (Groq)
# LLM_API_KEY=sk-or-... (OpenRouter)
npm run dev
The provider is detected from the key prefix (or set LLM_PROVIDER). The header badge shows Demo mode or
Live · model-name; GET /api/status reports the same in JSON.
| Command | What it does |
|---|---|
npm run dev / build / start | Next.js dev server / production build / production server |
npm run lint · npm run typecheck | ESLint · TypeScript |
npm test | Vitest unit + API tests (73) — PDF extraction, chunking, retrieval, grounding validation, scoring, tracing geometry, lesson data, route handlers, live-mode adapter with a mocked provider |
npm run test:e2e | Playwright end-to-end tests (18, desktop + phone) against a production build in forced demo mode. Uses the installed Chrome (channel: "chrome"); run npx playwright install chromium and remove channel to use bundled Chromium |
npm run assets:audio | Regenerates the bundled voice clips (needs Python edge-tts + network) |
npm run assets:glyphs | Rebuilds Hindi letter outlines from the Baloo 2 font |
npm run assets:pictures | Downloads the picture SVGs (Noto Emoji) |
npm run assets:samples | Rebuilds public/samples/*.pdf from the demo reader text |
All generated assets are committed, so none of the assets:* scripts are needed to run the app.
Everything is optional. Keys are read only on the server (import "server-only") and never reach the browser.
| Variable | Purpose | Default |
|---|---|---|
LLM_API_KEY | Key for the model provider (or use GEMINI_API_KEY / GROQ_API_KEY / OPENROUTER_API_KEY) | — (demo mode) |
LLM_PROVIDER | gemini · groq · openrouter · openai · custom | auto-detected |
LLM_MODEL | Model name | gemini-2.5-flash · llama-3.3-70b-versatile · google/gemini-2.5-flash · gpt-5-mini |
LLM_BASE_URL | OpenAI-compatible endpoint (required for custom) | preset |
LLM_REASONING_EFFORT | low/medium/high for models that accept it | low for gpt-oss, otherwise unset |
GROUNDING_JUDGE | Second-stage AI evidence check on answer keys | true in live mode |
LLM_TIMEOUT_MS | Per-request timeout | 90000 |
EMBEDDING_PROVIDER / EMBEDDING_API_KEY / EMBEDDING_MODEL / EMBEDDING_DIMENSIONS | Embeddings for hybrid retrieval. Automatic with a Gemini or OpenAI key; Groq/OpenRouter have no embeddings API, so pair them with a Gemini key here or run BM25-only | auto / none |
UPSTASH_REDIS_REST_URL / UPSTASH_REDIS_REST_TOKEN (or Vercel's KV_REST_API_URL / KV_REST_API_TOKEN) | Durable storage for uploads, quizzes and attempts | unset → local files |
DATA_DIR | Local storage folder | .data (or /tmp/alp-data on Vercel) |
MAX_UPLOAD_MB / MAX_PDF_PAGES | Upload limits (enforced in UI and API) | 15 / 250 (capped at 4.5 MB on Vercel — see below) |
DEMO_MODE | Force deterministic demo behaviour even with a key |
The PRD's DATABASE_URL / OBJECT_STORAGE_* are not used: persistence is Upstash Redis (REST, serverless-safe), and
PDFs are not stored after extraction — only their page text and chunks.
PDF ──► validate (type, size, %PDF magic, page limit)
──► extract per-page text (unpdf / PDF.js text layer) ── no text? → "looks scanned" error
──► detect chapters ("Unit 2 —", "Chapter 3", "पाठ 4"; contents pages ignored)
──► page-bounded, paragraph-aware chunks (~500 tokens, ~100 overlap) + metadata
──► (optional) embeddings ──► store
Quiz config ──► scope filter (chapter / page range) ──► context selection
(whole scope if it fits; else BM25 ⊕ embeddings via reciprocal-rank fusion, ≤2 chunks per page)
──► generate (live model, or demo generator)
──► rule checks ──► dedupe ──► optional AI evidence judge ──► reviewable quiz
src/lib/tutor/validate.ts): citations must point at chunks that were actually supplied;
quotes must appear on the cited page; page numbers always come from chunk metadata, never from the model;
MCQs need 2–4 distinct options and exactly one valid key; blanks need a visible ___ and an accepted answer that
occurs in the evidence; rubric points must sum to the max (auto-corrected and flagged); answers must be supported
by the cited text. Problems that make a question unscorable remove it (with a warning); anything else marks it
Needs review. Fewer questions are returned rather than padding with unsupported ones.S1…), which are mapped back server-side.toStudentQuestion, covered by tests).src/lib/early/lessons.ts): English A–Z (2–3 picture words each, letter name + "A for apple" cue +
adult-facing phoneme hint) and Hindi: 10 vowels + 8 consonants with romanised glosses.en-IN/hi-IN voice; if neither can
play, the UI says so and offers read-aloud text — it never pretends audio played. New audio always stops the
previous sequence; leaving a letter stops speech.src/lib/early/geometry.ts, src/components/early/trace-board.tsx): English guides are hand-authored
SVG stroke paths with numbered start dots, direction arrows and an animated "Show me". Hindi guides are the exact
SVG outline of each letter (Baloo 2); its centre line is computed at runtime by rasterising that same path and
thinning it (Zhang–Suen). Ink is stored in normalised 0..1 coordinates. Coverage = share of guide samples with
ink within ~5.5% of the board; an on-guide ratio catches scribbles. ≥70% coverage with ≥55% on-guide → success;
partial traces name the weakest stroke ("Trace line two again") or Hindi region (top line / left / right).
Low scores never block moving on. touch-action: none is applied to the canvas only.localStorage (explored / traced / attempts / last letter), with a reset in the
grown-ups panel. Nothing is sent to the server.src/app/ routes (App Router) + API route handlers under src/app/api
tutor/(workspace)/ teacher pages: dashboard, document/[id], generate, review/[id]
tutor/(student)/ student pages: quiz/[id], results/[id] (no teacher navigation)
early/[language]/[letter] lessons and /trace (all prerendered via generateStaticParams)
src/lib/tutor/ pure logic: types, schemas, pdf, chunk, retrieve, validate, score, demo bank
src/lib/ai/ provider config, OpenAI-compatible client, generate / evaluate / judge / embed tasks
src/lib/server/ services: ingest, generate, attempts, review, http helpers
src/lib/store/ KV (file · Upstash · memory) + repositories
src/lib/early/ lessons, strokes, glyph outlines, geometry & scoring, audio engine, progress
src/components/ UI (tutor/, early/, ui/)
tests/ Vitest unit + API tests; tests/e2e Playwright specs
scripts/ asset generators
POST/GET /api/documents · GET/DELETE /api/documents/:id (?page=N for a page's text) ·
POST /api/quizzes/generate (NDJSON progress stream) · GET /api/quizzes · GET/DELETE /api/quizzes/:id ·
PATCH/DELETE /api/quizzes/:id/questions/:qid · POST /api/quizzes/:id/questions/:qid/regenerate ·
POST /api/quizzes/:id/attempts · GET /api/attempts/:id · POST /api/attempts/:id/submit ·
GET /api/attempts/:id/results · GET /api/early/lessons?language=en|hi · GET /api/early/lessons/:language/:character ·
GET /api/status. All inputs are validated with Zod; errors are { error: { message } } without stack traces.
Uploads, generation and submissions are rate-limited per IP (best effort, per instance).
LLM_API_KEY (and LLM_MODEL), and for
durable data add Upstash Redis from the Vercel Marketplace (it injects KV_REST_API_URL / KV_REST_API_TOKEN).vercel (preview) / vercel --prod.Platform notes:
/tmp and can disappear — the UI shows a
"temporary" notice. The demo reader and all Early Learning content are built in and always available.maxDuration (60–120 s).npm test — 73 Vitest tests (unit + route-handler/API) including: answer keys never sent before submission;
demo mode with no key; invalid model JSON → one retry → safe failure; provider auth errors hidden; unsupported
citations rejected; MCQ determinism; fill-blank normalisation; rubric scoring clamped and flagged; scanned and
oversized PDFs; coordinate normalisation and coverage tiers (empty / partial / full / scribble).npm run test:e2e — 18 Playwright tests: full teacher → student → results flow, upload + preview + scanned
error, setup validation, lesson audio/navigation, tracing (empty, partial with stroke hint, full, undo, guide
toggle, show me), Hindi lesson, progress reset, no horizontal scroll at phone width, canvas-only scroll blocking.| Check | Status |
|---|---|
| Home on desktop and mobile | ✅ automated (layout) + manual screenshots |
| Generate a quiz from demo content | ✅ automated |
| Upload a searchable PDF; pages preserved | ✅ automated (public/samples/sunny-steps-demo-reader.pdf) |
| Invalid and oversized files | ✅ automated (API) + UI message |
| MCQ, fill-blank, short-answer and comprehension questions | ✅ demo bank; live mode needs a key |
| Citations support the question | ✅ citation drawer highlights the quote on the page |
| Edit a question, start a quiz | ✅ automated |
| Correct and incorrect MCQ scoring | ✅ automated |
| Semantically correct short answer, different wording | ⚠️ needs live mode (demo uses keywords) |
| English A: letter audio + two example words | ✅ automated (captions) — listen manually for audio quality |
| Hindi lesson: glyph rendering + audio fallback | ✅ glyphs automated; audio fallback by design |
| Trace with mouse and touch; clear and retry | ✅ mouse automated; touch uses the same pointer events — verify on a device |
| High, partial and empty traces | ✅ automated |
| Navigate letters while audio plays | ✅ audio stops on navigation |
| Refresh: persistence explained | ✅ storage notice in the tutor; progress in localStorage |
| Build and tests, no console errors | ✅ |
Implemented: everything in the PRD's M1–M5 milestones, plus provider-agnostic live AI (Gemini, Groq, OpenRouter, OpenAI, any OpenAI-compatible endpoint), hybrid retrieval, an optional AI grounding judge, question regeneration, Upstash persistence, NDJSON progress streaming, and the automated test suites above.
Deferred / limitations — please read before relying on the prototype:
reviewed: false). Voice clips are machine-generated placeholders
(Microsoft Edge neural TTS: en-IN-NeerjaNeural, hi-IN-SwaraNeural); record real audio before classroom use.src/lib/tutor/demo-textbook.ts).next/font (SIL OFL). Hindi outlines derive from Baloo 2.npm run dev; check GET /api/status → demoReason.LLM_MODEL isn't available for that provider/key. List models
with curl -H "Authorization: Bearer $KEY" <base-url>/models.npx playwright install chromium and remove channel.false |
PUBLIC_APP_URL | Sent as HTTP-Referer to OpenRouter | http://localhost:3000 |