Skip to content

lxcario/Nora

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

78 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Nora β€” Pixel Study OS

Nora

A softer way to study.
Evidence-based learning wrapped in a cozy pixel-art world β€” where your companion grows as you master what you study.

Nora in action


Why Nora

Most study apps are timers with a coat of paint, or AI that does the work for you. Nora is neither.

It's a study operating system built on six learning strategies from cognitive science, and a pixel-art world that only grows when your understanding does. The AI never writes your assignments β€” it asks questions, finds your gaps, and helps you plan. Your pet's mood reflects your real habits, not a streak counter you can game.

Learning first. AI as a tutor, never the author. Grounded data only β€” never fabricated claims.


What's inside

🧠 Feynman Mode β€” Grounded Evaluation

Explain a concept in plain words and an AI "Inquisitive Student" probes it back β€” colour-coded gap analysis (green / amber / red), clarifying questions, and one-click flashcards from your own explanation.

Source grounding (new): Attach an indexed paper, video transcript, or pasted notes to any topic. Evaluation then grades your explanation strictly against those passages, citing the specific passage that each amber/red segment contradicts or omits. Without a source, feedback is clearly labelled "unverified (no source attached)" β€” no fabricated specifics presented as fact.

πŸ” FSRS Spaced Repetition

A full FSRS-6 scheduler (via ts-fsrs, MIT) drives the review queue. FSRS reduces review load ~20–30% vs SM-2 and eliminates "Ease Hell" by using a DSR memory model (Difficulty, Stability, Retrievability).

  • Four-button grading: Again / Hard / Good / Easy (mapped to FSRS Rating).
  • Intra-session relearning: A lapsed card (Again) re-queues within the current session.
  • Timezone-safe due dates: "Due today" is determined by profiles.timezone, never the server's local clock.
  • Cards from Feynman, research, video study, and manual entry all flow into the same FSRS queue.

SM-2 columns were preserved during backfill and removed after verification (migration 016).

πŸ”€ Evidence-Based Study Mix

Mixed practice queue built on the Brunmair & Richter (2019) meta-analysis:

  • verbal_vocabulary topics β†’ blocked (never interleaved) β€” interleaving hurts word-list recall (g = βˆ’0.39).
  • procedural_math and visual_discrimination β†’ interleaved within confusable same-subject topics (g = 0.34–0.67).
  • Queue weighted toward weakest topics using FSRS difficulty (70%) and inverse Feynman comprehension score (30%).
  • Queue size scales to the actual due-card load (no fixed cap).

Set each topic's material type in Settings β†’ Subjects.

🎬 Video Study Room

YouTube search with educational filtering, transcript extraction (with Groq Whisper fallback), timestamp-aware AI notes in a Tiptap editor with clickable time marks, inline ghost-text completions, and "explain what you just watched" Feynman evaluated against the transcript.

πŸ”¬ Research Desk β€” Real Academic Sources

Web research now uses real academic APIs instead of Wikipedia/Open Library:

API Role License
OpenAlex Primary β€” CC0 scholarly catalog CC0
Crossref Supplementary DOI/metadata Free Polite Pool
Unpaywall Open-access PDF discovery Free

Every citation maps to a retrieved source. When fewer than 2 sources are found the system says so β€” it never fabricates a literature review. Synthesis is constrained to retrieved abstracts; model supplementation is clearly labelled "unverified."

One-click "Ingest Open Access PDF": looks up a DOI via Unpaywall β†’ SSRF-checks the URL β†’ runs it through the full Paper RAG pipeline.

πŸ“„ Hybrid Paper RAG

Dual-mode retrieval fused with Reciprocal Rank Fusion (RRF):

  • Vector leg β€” pgvector cosine similarity (text-embedding-3-small, 1536 dims).
  • Lexical leg β€” ts_rank_cd over a generated tsvector GIN index (always available).
  • When no embedding key is configured β†’ ranked lexical-only (never an unranked scan).
  • Citations reference the actual retrieved chunk (paper title, section, chunk index) β€” no default-to-zero fallback.

πŸŽ“ University-Aware Onboarding

Tell Nora your university, faculty, department, year, and term. It finds your institution's official academic data β€” academic calendar, registration/add-drop/midterm/final dates, holidays, and curriculum β€” stores the official PDFs, indexes them, and uses them to build a semester-aware study plan and an academic RAG you can ask about your own semester.

  • Diacritic-insensitive Turkish-aware matching (ODTÜ / METU first launch)
  • Never invents dates β€” ungrounded dates are dropped; missing official dates are stored as unreleased
  • Background ingestion via an ingestion_jobs queue; manual upload always works

πŸ“… Spacing-Aware Planner

Session distribution using the Cepeda et al. (2008) temporal ridgeline β€” optimal interstudy gap as a function of days-until-exam:

  • Sessions spread across the week with expanding gaps (not crammed to today).
  • Asymmetric cost principle β€” when the ideal gap is uncertain, gaps err wider (under-spacing is far costlier than over-spacing).
  • Near-exam boost β€” subjects with exams within 14 days get FSRS request_retention = 0.95 instead of capping intervals.
  • Missed-session forward-fill β€” marking a session missed reschedules it to the next free day without compressing the rest.
  • Academic event merge: confirmed semester events surface as calendar chips and warning strips.

🐾 Pixel Room & Pet

Pick from 12 animated companions. Your pet evolves with your level and its mood mirrors your last few days of study. Daily missions tie directly to real study actions.

πŸ‘₯ Social Parties

Create or join study groups, share weekly quests, and send cheers. Missed days become compassionate "help quests" for the group instead of punishing resets.

πŸ“Š Analytics

Weekly stats, 30-day charts, a GitHub-style consistency heatmap, and topic mastery bars.


Gamification

Action XP Coins Affinity
Feynman explanation +15 +5 +3
Card review (Good/Easy/Hard) +3 +1 +1
Card review (Again β€” lapse) +1 β€” β€”
Card created +2 β€” β€”
Study session complete +10 +3 +2
All daily missions +20 +10 +5

Level: floor(sqrt(xp / 50)) + 1 β€” Lv2 at 50 XP, Lv3 at 200, Lv4 at 450, Lv5 at 800.

8-bit sound effects generated live with the Web Audio API β€” no audio files, just procedural oscillators with a sidebar mute toggle.


Tech Stack

Layer Technology
Framework Next.js 16 (App Router, Server Actions)
Language TypeScript strict β€” Node.js β‰₯ 20
UI React 19, Tailwind CSS v4, custom pixel-UI components
Database Supabase β€” Postgres, pgvector, RLS, Storage
Auth Supabase Auth (gated via proxy.ts)
Spaced Repetition ts-fsrs (MIT) β€” FSRS-6 DSR model
AI (primary) Groq Cloud (Llama 3.3 70B)
AI (fallback) OpenRouter (free tier)
Academic Sources OpenAlex (CC0), Crossref Polite Pool, Unpaywall
RAG retrieval pgvector cosine + ts_rank_cd FTS β†’ RRF
Rich text Tiptap v3 (custom timestamp mark)
PDF parsing pdf-parse (default); unpdf optional (Node β‰₯ 22)
Testing Vitest + fast-check (property-based) β€” 332 tests

Getting Started

Prerequisites

  • Node.js β‰₯ 20 (required by ts-fsrs)
  • A Supabase project (free tier works)
  • A Groq API key (free at console.groq.com)

Setup

git clone https://github.com/lxcario/Nora.git
cd Nora
npm install
cp .env.example .env.local
# Edit .env.local with your keys

Environment

See the full variable reference in .env.example. Minimum to run:

NEXT_PUBLIC_SUPABASE_URL=...
NEXT_PUBLIC_SUPABASE_ANON_KEY=...
GROQ_API_KEY=...
Variable Required Purpose
NEXT_PUBLIC_SUPABASE_URL βœ… Supabase project URL
NEXT_PUBLIC_SUPABASE_ANON_KEY βœ… Supabase anon key
GROQ_API_KEY βœ… LLM β€” Feynman, research, synthesis
OPENROUTER_API_KEY optional LLM fallback
OPENAI_API_KEY optional Enables pgvector RAG (FTS used otherwise)
OPENAI_EMBEDDING_MODEL optional Defaults to text-embedding-3-small (1536 dims)
ACADEMIC_API_MAILTO recommended OpenAlex + Crossref Polite Pool enrollment
ACADEMIC_API_EMAIL recommended Unpaywall API access β€” required for OA PDF ingestion
NEXT_PUBLIC_SUPPORT_EMAIL fallback Used if specific mailto/email vars are absent
FIRECRAWL_API_KEY optional University auto-discovery (manual upload always works)
YOUTUBE_API_KEY optional YouTube search in Study Room
NEXT_PUBLIC_SITE_URL optional OpenRouter attribution headers

Academic APIs (OpenAlex, Crossref, Unpaywall) are free with no key required, but passing your email in ACADEMIC_API_MAILTO / ACADEMIC_API_EMAIL enrolls the app in the Polite Pool for higher rate limits and is required by Unpaywall's terms of service.

Database Migrations

Run all migrations in order via the Supabase SQL Editor or supabase db push:

supabase/migrations/001_initial_schema.sql       # core schema
supabase/migrations/002_social_parties.sql       # party tables
supabase/migrations/003_avatar_storage.sql       # avatar storage
supabase/migrations/003_rag_extensions.sql       # FTS, match_paper_chunks RPC
supabase/migrations/003b_storage_bucket.sql      # PDF storage bucket
supabase/migrations/004_study_room.sql           # video / transcript tables
supabase/migrations/005_party_rls_fix.sql        # RLS fix
supabase/migrations/006_feynman_scoring.sql      # comprehension score column
supabase/migrations/007_university_onboarding.sql # academic profile / events
supabase/migrations/008_ingestion_jobs.sql       # background job queue
supabase/migrations/009_academic_sweeper.sql     # academic data sweeper
supabase/migrations/010_fsrs_scheduling.sql      # FSRS columns on cards
supabase/migrations/011_material_type.sql        # topic material_type
supabase/migrations/012_hybrid_search.sql        # match_paper_chunks_hybrid RPC
supabase/migrations/013_research_sources.sql     # doi + oa_url on papers
supabase/migrations/014_feynman_source_attachment.sql  # feynman_source_ref on topics
supabase/migrations/015_planner_skips.sql        # planner missed-session records
supabase/migrations/016_drop_sm2_columns.sql     # removes SM-2 columns (run LAST)

Migration 016 is destructive. Run it only after verifying that all production cards have non-NULL due values (i.e., after Task 2's initFromSM2 backfill has completed successfully).

Then seed the university registry:

supabase/seed_university_registry.sql

Run

npm run dev

Open http://localhost:3000, sign up, and start studying.


Testing

npm test            # run all tests once (332 passing)
npm run test:watch  # watch mode

Tests use Vitest + fast-check (property-based). Coverage includes:

  • FSRS scheduling (FSRS-1, FSRS-2 properties)
  • SM-2 β†’ FSRS migration backfill (no NaN/negative; no all-same-day)
  • Timezone-safe due-date helpers (DUE-1 across 9 IANA zones + DST)
  • RRF fusion ordering on known inputs
  • Citation validation β€” every emitted citation resolves to a retrieved chunk (RAG-1)
  • Academic search API clients with mocked fetch (graceful no-key/empty handling)
  • Research citation validation β€” no unsupported [N] markers (RESEARCH-1)
  • Feynman grounding helpers (passage building, prompt constraints)
  • Study Mix queue builder β€” vocab blocking (MIX-1), weakness ordering (MIX-2)
  • Spacing math β€” non-decreasing gaps, never past the exam (SPACING-1)
  • Planner forward-fill β€” result strictly after original, never in occupied set

Project Structure

src/
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ (auth)/                     # Login / signup
β”‚   └── (protected)/app/
β”‚       β”œβ”€β”€ _actions/               # Server actions
β”‚       β”‚   β”œβ”€β”€ review.ts           # FSRS review queue + submit
β”‚       β”‚   β”œβ”€β”€ feynman.ts          # Grounded Feynman evaluation + source attachment
β”‚       β”‚   β”œβ”€β”€ research.ts         # Grounded synthesis (OpenAlex/Crossref/Unpaywall)
β”‚       β”‚   β”œβ”€β”€ rag.ts              # Hybrid RAG (RRF retrieval)
β”‚       β”‚   β”œβ”€β”€ planner.ts          # Spacing-aware planner + missed-session reschedule
β”‚       β”‚   β”œβ”€β”€ study-session.ts    # Evidence-based Study Mix queue
β”‚       β”‚   β”œβ”€β”€ subjects.ts         # Material-type management
β”‚       β”‚   β”œβ”€β”€ academic/           # University onboarding, registry, ingest, jobs
β”‚       β”‚   └── rag/                # parser, chunker, embedder sub-modules
β”‚       β”œβ”€β”€ feynman/                # Feynman editor with source attachment UI
β”‚       β”œβ”€β”€ review/                 # FSRS review session (4-button, intra-session relearning)
β”‚       β”œβ”€β”€ research/               # Research Desk (OpenAlex + OA PDF ingestion)
β”‚       β”œβ”€β”€ settings/               # Settings including material-type selector
β”‚       └── …
β”œβ”€β”€ lib/
β”‚   β”œβ”€β”€ fsrs.ts                     # Pure FSRS module (scheduleReview, initFromSM2)
β”‚   β”œβ”€β”€ due.ts                      # Timezone-safe due-date helpers
β”‚   β”œβ”€β”€ rrf.ts                      # Reciprocal Rank Fusion (mirrors SQL function)
β”‚   β”œβ”€β”€ feynman-grounding.ts        # Passage building + grounded prompt construction
β”‚   β”œβ”€β”€ study-mix.ts                # Evidence-based queue builder (buildQueue)
β”‚   β”œβ”€β”€ spacing.ts                  # Cepeda ridgeline + distributeSessions
β”‚   β”œβ”€β”€ academic-search/
β”‚   β”‚   β”œβ”€β”€ openalex.ts             # OpenAlex client (CC0)
β”‚   β”‚   β”œβ”€β”€ crossref.ts             # Crossref Polite Pool client
β”‚   β”‚   β”œβ”€β”€ unpaywall.ts            # Unpaywall OA lookup + enrichWithUnpaywall
β”‚   β”‚   └── types.ts                # Shared AcademicWork / UnpaywallResult types
β”‚   β”œβ”€β”€ academic/                   # University pure libs (registry, load, extract…)
β”‚   β”œβ”€β”€ sm2.ts                      # SM-2 (retained as migration reference, no longer used)
β”‚   └── supabase/                   # Typed clients
β”œβ”€β”€ supabase/
β”‚   β”œβ”€β”€ migrations/                 # 001–016
β”‚   └── tests/
β”‚       └── 012_hybrid_search.test.sql  # SQL fusion-ordering test (run with psql)
└── proxy.ts                        # Auth gate

Optional External Services

The following tools are not required and not part of the runtime path. They are documented here for operators who want to extend the pipeline.

Docling (PDF extraction)

Docling provides higher-fidelity PDF parsing (tables, figures, complex layouts) than pdf-parse. It is a Python service that runs outside Next.js. To use it:

  1. Run Docling as a sidecar service (Docker).
  2. Call its REST API from a custom server action before calling chunkText.
  3. Docling is never a hard dependency β€” pdf-parse is always the default.

Ragas (RAG evaluation)

Ragas is a Python library for evaluating retrieval-augmented generation pipelines. It can score faithfulness, answer relevance, and context precision of queryRag responses offline. To use it:

  1. Export a sample of (question, answer, contexts) triples from your production logs.
  2. Run Ragas in a Python notebook or CI script against those triples.
  3. Ragas does not run inside Next.js and is not installed as a dependency.

Design Philosophy

  1. Learning over engagement β€” every mechanic maps to real study behavior.
  2. AI as tutor, not author β€” it questions and guides; never writes your work.
  3. Grounded data only β€” official academic sources only; no invented dates, no fabricated citations, ever.
  4. Compassionate design β€” no punishment for missed days; the group helps instead.
  5. Evidence-based defaults β€” interleaving, FSRS, and spacing choices are backed by published meta-analyses with explicit citations in the code.
  6. Reuse over rebuild β€” new features ride the existing Supabase + Server Actions architecture.

Evidence Base

Feature Source
FSRS scheduler Ye (2022), DSR model β€” reduces review load ~20–30% vs SM-2
Vocab blocking Brunmair & Richter (2019) β€” g = βˆ’0.39 for word lists
Math/visual interleaving Brunmair & Richter (2019) β€” g = 0.34 (math), 0.67 (discrimination)
Spacing ridgeline Cepeda et al. (2008) β€” optimal lag ratio by retention interval
Asymmetric spacing cost Cepeda et al. (2008) β€” under-spacing harms far more than over-spacing
Self-explanation grounding Chi (2000); Fiorella & Mayer (2016) β€” strongest when checked against sources

Credits & Licenses

  • ts-fsrs β€” MIT β€” FSRS-6 scheduling library
  • Sprout Lands UI Pack by Cup Nooble β€” pixel font and UI elements
  • Lucide β€” MIT icons
  • Tiptap β€” MIT rich text editor
  • OpenAlex β€” CC0 scholarly metadata
  • Crossref β€” free Polite Pool metadata service
  • Unpaywall β€” free open-access PDF registry

University academic data is sourced from official institutional portals and treated as untrusted, read-only input.


License

MIT

Built with pixels, science, and a lot of coffee.
Nora β€” a softer way to study.

About

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors