TutorLoom
기업·대학·교육기관을 위한 학습 플랫폼, 무료 오픈소스이며 엔터프라이즈 버전 제공
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
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