Back to selected work

Personal Project

Kotoba Tabi

A bilingual Japanese–Indonesian learning app with RPG-style quest progression, seeded encounter quizzes, and an adaptive review queue — built for real-life scenarios, not textbook drills.

I built this because no existing app handles the JP↔ID learning pair well. Duolingo's Indonesian course is thin. Anki is powerful but blank. I wanted scenario-based learning — konbini, train station, hospital — with enough game loop to sustain a daily habit, and enough engineering under the hood to make the content extensible via Supabase without a re-deploy.

Core goal

Scenario-first, habit-sustaining

Every quest is grounded in a real-life scene. The RPG mechanics — XP, streaks, badges, placement — exist to keep the learning loop honest, not to gamify for its own sake.

Stack

Next.js + Supabase

Next.js App Router for the frontend, Supabase as the remote content catalog, bundled JSON fallback for offline launch.

Directions

JP→ID and ID→JP

Direction switching is a first-class feature — the entire quest map, quiz bank, and review queue swap based on the selected learning direction.

Quiz engine

Seeded random

Encounter sets are generated with a seeded PRNG — reproducible, balanced across skills, and deduplicated per session.

Review queue

Missed-question tracking

Wrong answers enter a review queue with difficulty ratings (lupa / sulit / oke / mudah) and timestamps for spaced re-exposure.

01

The Problem

Indonesian learners have almost no purpose-built tools for Japanese. The reverse is equally sparse. Generic apps like Duolingo don't surface the structural differences between Indonesian and Japanese sentence patterns, and they're not built around the real-life situations most relevant to learners in Japan — convenience stores, transit, clinics, offices. Anki covers vocabulary but not scenario comprehension or grammar in context.

02

Quiz Engine Design

The quiz engine uses a seeded PRNG to generate reproducible encounter sets from a content bank. Questions are selected to cover all skills (kana, kanji, vocabulary, grammar, dialogue, survival) before repeating any, and deduplicated per session. Seeding means the same quest always produces the same question order — useful for content testing and consistent difficulty.

  • Seeded Fisher-Yates shuffle for reproducible, balanced question selection
  • Skill-first selection ensures every encounter covers all question types before repeating
  • Option IDs (A/B/C/D) re-assigned after shuffle — no positional bias in correct answers
  • Question bank keyed by quest and skill for fast lookup and per-quest filtering

03

Review Queue

Missed questions don't disappear — they enter a review queue with metadata: which quest, which skill, what the correct answer was, how many times it's been missed, and when it was last reviewed. Users rate each review item by difficulty, and the queue surfaces items that haven't been reviewed recently first.

  • Review items track questionId, questId, skill, mistakes count, and timestamps
  • Difficulty rating (lupa / sulit / oke / mudah) recorded per review session
  • Queue sorted by lastReviewedAt null-first for freshness-based re-exposure
  • Persisted to localStorage with typed validation on hydration

04

Content Architecture

Content lives in two layers: a bundled JSON pack shipped with the app (zero-dependency launch), and a Supabase content catalog gated by a feature flag. When the flag is on and Supabase is reachable, the app fetches the remote catalog and merges it with the local pack. If Supabase is unavailable, it falls back to bundled content silently.

  • NEXT_PUBLIC_SUPABASE_CONTENT_ENABLED flag gates all remote content fetches
  • Bundled content-pack.ts ships N5 starter content — app works offline from day one
  • Supabase catalog allows content updates without a re-deploy
  • Bilingual content: separate quest maps and quiz banks per learning direction

05

Outcome

Live at nihongo-quest-pi.vercel.app with N5 JP→ID content, a working quest map, placement test, daily dashboard, and adaptive review queue. Indonesian content for Japanese learners is also live. The Supabase content pipeline is wired — adding new quests is a database write, not a code change.

Continue Exploring

LINE × Kintone Integration is also live.

Each case study covers a different part of the stack — see how the same engineering principles show up across different problem types.

Read LINE × Kintone Integration