Free, interactive nutrition courses in English and Hindi — 3 courses, 36 lessons, for kids through adults.
Live: nutristep.vercel.app
Each lesson is a short, sequential story rather than a quiz or a game:
Hook → What it is → How it works → Worked example
→ Try-it activity (gated) → Quiz (gated) → Recap + celebration
The interactions live inside the lesson, not instead of it. You can't skip the hands-on step — the Next button stays locked until the activity is actually completed.
| Course | Audience | Lessons |
|---|---|---|
| Nutrition Basics | Everyone | 18 |
| Energy Balance | Teens and up | 9 |
| Weight Management | Adults | 9 |
Around the lessons sits a Duolingo-inspired layer that rewards effort and never punishes a mistake — no hearts, no timers, no leaderboards.
- Nori, the mascot: the logo apple come alive, in seven moods (happy, cheer,
think, oops, proud, sleepy, idle). Pure SVG with hand-written CSS keyframes —
no animation library, no JS, and it holds still under
prefers-reduced-motion. - XP, levels and a daily goal. +10 for a new lesson, +5 bonus for a perfect quiz, +5 for a replay, points for review mode, +10 for opening a unit's chest.
- Streaks with a shield. Learn something each day to keep the flame lit; one missed day a week is forgiven, so a busy day doesn't wipe out a habit.
- Feedback that feels alive. Answer sheets slide up with Nori's reaction and a combo counter; progress segments shine as they fill; finishing a lesson plays a staged celebration — stats counting up, the streak ticking, then any level-up or new badge.
- A winding path per course: unit banners, round lesson stops, stars for perfect lessons, Nori at "you are here", and a treasure chest closing each unit.
- Sound and vibration, synthesised in the browser with the Web Audio API (no audio files), behind one mute switch in the header.
- Badges with tiers. Course and unit milestones, plus bronze / silver / gold challenges for streaks, perfect lessons, reviews and XP, each with a progress bar.
- Nori's wardrobe. Outfits (sweatband, smart glasses, party hat, chef's hat, crown) unlock by level and badges; the one you pick shows on every Nori in the app.
Lesson content is typed TypeScript, not JSON. Every English lesson module is
satisfies LessonMap, and every Hindi module is satisfies typeof <english module>.
A translation cannot drop a key, rename a card id or mistype a field without
failing the build — which is the difference between a missing translation being a
compile error and being a blank card in production. Locale JSON holds UI strings
only (~8 KB instead of ~105 KB).
Progress is local-first. It lives in localStorage behind a
useSyncExternalStore store and works with no account at all. Signing in adds a
Firestore sink on top; it never becomes a prerequisite. Firebase itself is loaded
through await import() only once a session actually needs it, which keeps ~650 KB
off the landing page for the majority of visitors who never sign in.
Badges are derived, not stored. evaluateBadges(facts) is a pure function of
saved progress (lessons done, perfect lessons, best-ever streak, reviews, XP), so
there is no second source of truth to fall out of sync — and a streak badge stays
earned after the streak ends, because "best streak" is computed from history.
XP is a ledger; streaks and levels are maths. The store saves only XP per local
day (plus perfect lessons and opened chests). Totals, levels, the streak and its
weekly shield are pure functions in lib/xp.ts, unit-tested day by day — and two
devices merge cleanly (union of lessons, per-day max of XP).
Everything is static. 173 prerendered routes, zero dynamic routes — including the legacy redirects. The whole site is a CDN artifact.
No raster or audio assets. Every illustration — foods, icons, badges and the mascot — is hand-built inline SVG, and every sound is synthesised at runtime, so the art is themeable and scalable and costs no image or audio requests.
Next.js 16 (App Router, Turbopack) · TypeScript · Tailwind CSS 4 · Framer Motion · Firebase Auth + Firestore (optional) · Vitest
A few Next.js 16 specifics worth knowing if you're reading the source: routing
middleware is proxy.ts (not middleware.ts), params and searchParams are
Promises and must be awaited, and directional page animations use the native
<ViewTransition> wrapper with transitionTypes on <Link>.
app/[lang]/ # locale-scoped routes (en, hi)
page.tsx # course library (landing)
learn/[course]/ # course roadmap
[module]/[chapter]/ # the lesson itself
dictionaries/{en,hi}.json # UI strings only
components/
story/ # the lesson engine: slides, quiz, answer sheet,
# end-of-lesson celebration, gating
chapters/ # per-lesson assembly + try-it activities
mascot/Nori.tsx # the mascot (motion lives in globals.css)
landing/ # library, Today panel, winding course path
badges/ icons/ ui/ # trophy shelf, SVG icons, header chips, shell
lib/
content/{en,hi}/*.ts # lesson text as typed modules
curriculum.ts # courses → modules → chapters (source of truth)
progress.tsx badges.ts # local-first store, derived badges
xp.ts sfx.ts # XP/level/streak maths, synthesised sound
tests/ # curriculum + content invariants, review picker,
# streak/level maths, progress migration + merge
Adding a lesson means adding it to the right course module in lib/content/en/,
mirroring it in lib/content/hi/, then wiring it in lib/curriculum.ts and the
router switch. The compiler reports anything you missed.
npm install
cp .env.example .env.local # optional — see below
npm run devOpen http://localhost:3000.
The .env.local step is optional. Omit the Firebase block entirely and the app
still works — every lesson, badge and progress feature runs on localStorage;
you just don't get accounts or cross-device sync. Fill it in to enable those.
NEXT_PUBLIC_SITE_URL only affects sitemap.xml, robots.txt and canonical
URLs, and is detected automatically on Vercel.
npm run dev # dev server (Turbopack)
npm run build # production build + type check
npm run lint # ESLint
npm test # Vitest — curriculum, content, badges, XP/streaks, progressdocs/ROADMAP.md— the course model, phased build plan and what's nextdocs/GAMIFICATION_PLAN.md— the gamification audit and phases K1–K6IMPROVEMENT_PLAN.md— the audit this was last measured againstCLAUDE.md— architecture and conventions, in depth
NutriStep is general health education, not medical advice. The adult weight-management course says so on its first lesson, and each course cites the WHO / NHS material it's based on at the bottom of its roadmap.