TutorLoom
The learning platform for companies, colleges and training institutes. Free and open source, with an Enterprise edition.
Learn to read hiragana with an endless, timed reading game.
Translation pending
EducationTypeScript · CSSGitHub @pawanrai100OnlineOwner 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 ↗An endless, timed hiragana reading game. Read real Japanese words and random kana combos, type the romaji, beat the clock. Built to grow into a full Japanese learning platform.
Next.js 16 (App Router) + TypeScript + Tailwind CSS v4 + shadcn-style components + Lucide icons. No database, API key or account needed. Progress lives in localStorage.
Needs Node 20.9+ (22 recommended).
npm install
npm run dev # http://localhost:3000
Other scripts:
npm test # vitest unit tests (quiz generation, grading, filtering, progress)
npm run typecheck # tsc --noEmit
npm run lint # eslint
npm run build # production build
npm start # serve the production build
git init, commit, push).main redeploys automatically. No environment variables needed.CLI alternative: npm i -g vercel && vercel from the project folder.
Optional. With no Supabase keys the site runs guest-only, exactly as before. Setup steps: SETUP-ACCOUNTS.md.
/login, /signup, /forgot-password, /reset-password, plus /auth/callback and /auth/confirm for email and Google links./profile: avatar, username, stats, password change, sign out (this device or everywhere), data download.localStorage keys. After signing in, users are asked once whether to add it to their account (a backup is kept).kana-dojo:v1:u:<id>:...) that syncs to one user_progress row. Saves happen locally first, then upload about 1.5 s later. It works offline and catches up when back online.rev number, and a stale save is rejected, merged and retried (src/lib/sync/).supabase/migrations/. Row Level Security limits every user to their own rows. supabase/tests/ has the SQL tests used to check it./leaderboard: weekly board of correct answers, for signed in users. 0002_leaderboard.sql adds a weekly_leaderboard() function that reads each user's synced day log and returns only name, belt and score, so progress stays private. Users can hide themselves in Settings.Where things live:
| Path | What |
|---|---|
src/lib/supabase/ | client setup, public key guard, safe redirects |
src/lib/sync/ | merge rules, sync engine, Supabase storage adapter (all unit tested) |
src/features/auth/ | auth provider (session + sync), login/signup/password forms |
src/features/profile/ | profile page |
src/store/app-store.ts | per-user local storage, guest import |
src/lib/quiz/timer.ts from its length, lookalike characters (ぬ/め, ね/れ/わ...), characters you're weak on, characters you've never seen, and whether it's a nonsense combo. The pace setting scales it (Relaxed ×1.6, Normal, Fast ×0.7), and Zen turns timers off. The clock pauses when the tab is hidden.| Key | Action |
|---|---|
| Enter | Lock in / next answer. Enter on the last one grades the round |
| Shift+Enter | Skip round (when shortcuts are on) |
| Enter or N | Next round after grading (when shortcuts are on) |
src/
app/ routes only, thin wrappers
layout.tsx fonts, no-flash theme script, app shell
page.tsx dashboard
practice/ chart/ progress/ settings/
globals.css design tokens (light + dark) and animations
components/
ui/ shadcn-style primitives (button, card, dialog, switch, misc)
layout/ app shell (sidebar + mobile tab bar), theme sync, page header
features/ one folder per product area
dashboard/
hiragana/practice/ the game: practice-game, question-card, round-summary, petals
hiragana/chart/ interactive chart + character detail dialog
progress/ stats page, svg charts, session list
settings/
lib/ pure logic, no React, fully unit-tested
kana/ character data (types.ts, hiragana.ts)
vocab/ word lists (hiragana-words.ts)
quiz/ generate.ts, validate.ts, grade.ts, timer.ts, adaptive.ts, session.ts
game/ scoring.ts (points, combos, stars, xp)
progress/ types, update.ts (fold a round in), stats.ts (derived numbers), sanitize.ts
settings/ types, defaults, sanitize
storage/ local.ts, the Repository interface over localStorage
modules.ts nav + "coming soon" module registry
sound.ts webaudio sound effects
store/app-store.ts single external store (useSyncExternalStore), all actions
| Feature | Where |
|---|---|
| Dakuten / handakuten / small kana | Add a new KanaSet next to HIRAGANA_BASIC_SET in lib/kana/hiragana.ts. Small kana combos (きゃ) need splitKana to group digraphs. Words go in lib/vocab/. Then widen resolveEnabled in lib/quiz/generate.ts, which is the single gate that enforces the v1 basic-46 rule. |
| Katakana | lib/kana/katakana.ts with the same KanaChar shape (script: "katakana"), a vocab file, and a features/katakana/ folder reusing the practice components. Flip it to live in lib/modules.ts. |
| Kanji / JLPT vocab | Extend VocabWord in lib/vocab/types.ts (it already has an optional jlpt field), add data files, and a new feature folder. |
| Spaced repetition / flashcards | Per-item stats already exist (CharStat, WordStat in lib/progress/types.ts). Add due dates there and a scheduler in lib/quiz/. Weighting lives in lib/quiz/adaptive.ts. |
| Audio / listening | Add audioUrl to VocabWord; play it from question-card.tsx. |
| Accounts + cloud sync | Implement the Repository<T> interface from lib/storage/local.ts against your API (Supabase, a Next.js route handler, etc.) and swap it in store/app-store.ts. Nothing else talks to storage. |
| AI lessons | A route handler under app/api/ plus a feature folder. The quiz engine takes any VocabWord[] via GenerateInput.vocab. |
| Timer tuning | lib/quiz/timer.ts (BASE_SEC, PER_KANA_SEC, PACE_MULT). |
| Scoring / levels | lib/game/scoring.ts and levelInfo in lib/progress/stats.ts. |
Stored data is versioned under the kana-dojo:v1: prefix and every read goes through a sanitizer, so corrupted or old data falls back to safe defaults instead of crashing. Bump the prefix if you ever change the shape incompatibly.
src/**/*.test.ts covers:
localStorage data