The /learning page on vachsark.com is a 1,329-line React component that serves as an interactive knowledge engine. It displays 10,800+ atomic notes across 28+ disciplines (Computer Science, Economics, Neuroscience, UX, Education, Mathematics, Psychology, and more), provides an FSRS-5 adaptive spaced repetition quiz system, and keeps private notes encrypted client-side with AES-GCM. The data pipeline that feeds it — a combination of automated research agents and AI review — runs independently in the vault's heartbeat system.
Three Tabs, Two Access Levels
The page has three tabs: Dashboard, Explorer, and Quiz. The Dashboard is public. Explorer and Quiz require unlocking with a password, which decrypts a separate data file (learning-private.enc.json) in the browser.
The Dashboard shows aggregate statistics pulled from a pre-generated JSON file:
// From learning-public.json
<Stat value={stats.total} label="Knowledge Notes" /> // 10,800+
<Stat value={stats.disciplines} label="Disciplines" /> // 28+
<Stat value={stats.confirmed} label="Confirmed" /> // 8,000+
<Stat value={stats.withPrerequisites} label="With Prerequisites" />Below the stats, a discipline breakdown renders horizontal progress bars. Each bar shows two layers — gold for total notes in that discipline, green for confirmed notes. Computer Science dominates with 2,100+ notes (1,600+ confirmed), followed by Economics (950+) and Neuroscience (800+).
Client-Side Encryption
Private notes never touch the server as plaintext. The encryption flow uses Web Crypto API with PBKDF2 key derivation and AES-GCM:
// Learning.jsx — decryptPrivateData
const keyMaterial = await crypto.subtle.importKey(
"raw",
new TextEncoder().encode(password),
"PBKDF2",
false,
["deriveBits", "deriveKey"],
);
const key = await crypto.subtle.deriveKey(
{ name: "PBKDF2", salt, iterations: 100000, hash: "SHA-256" },
keyMaterial,
{ name: "AES-GCM", length: 256 },
false,
["decrypt"],
);
const decrypted = await crypto.subtle.decrypt(
{ name: "AES-GCM", iv },
key,
rawData,
);
return JSON.parse(new TextDecoder().decode(decrypted));The encrypted payload stores salt, IV, and ciphertext as base64 strings. 100,000 PBKDF2 iterations provide reasonable brute-force resistance while keeping decryption near-instant on modern hardware. On success, the decrypted note data is held in component state — it never persists to disk or localStorage.
The Explorer
Once unlocked, the Explorer tab provides full-text search across all notes with discipline filtering. Each note expands to show its summary, key points, prerequisite chain, and cross-connections to other notes.
// Learning.jsx — Explorer search filter
const filtered = useMemo(() => {
let result = notes;
if (discipline) result = result.filter((n) => n.discipline === discipline);
if (query.trim()) {
const q = query.toLowerCase();
result = result.filter(
(n) =>
n.title.toLowerCase().includes(q) ||
n.summary.toLowerCase().includes(q) ||
n.keyPoints.some((kp) => kp.toLowerCase().includes(q)) ||
n.tags.some((t) => t.toLowerCase().includes(q)),
);
}
return result;
}, [notes, discipline, query]);The search covers title, summary, key points, and tags. Prerequisite and connection badges resolve to actual note objects via ID lookup, rendering as clickable chips that show the linked note's title.
Adaptive Spaced Repetition (FSRS-5)
The Quiz tab implements FSRS-5 (Free Spaced Repetition Scheduler), an adaptive algorithm that personalizes review intervals based on performance. FSRS replaces the earlier fixed-interval Leitner system. Review intervals are calculated dynamically to optimize for target retention rates (typically 85%), reducing review load by 20-30% compared to fixed-interval systems like Leitner.
// Learning.jsx — FSRS SRS (replaces legacy Leitner)
// FSRS calculates due dates dynamically based on performance
import { fsrs, Rating, State } from "ts-fsrs";
function getDueNotes(notes, srsState) {
const today = getToday();
const due = [];
const unseen = [];
for (const note of notes) {
if (note.keyPoints.length < 2) continue;
const state = srsState[note.id];
if (!state) {
unseen.push(note);
} else if (state.due <= today) {
due.push(note);
}
}
return { due, unseen };
}Notes need at least 2 key points to be quizzable. Each quiz session presents 5 cards, drawn from due notes first, then unseen notes, both shuffled. The quiz format is retrieval practice — the note title and discipline are shown, and the user attempts to recall the key points from memory before revealing the answer. Correct answers update the FSRS card state to increase spacing; incorrect answers reduce the interval for next-day review. FSRS parameters (stability, difficulty) update automatically based on response quality and latency.
SRS state persists in localStorage via a useLocalStorage hook, keyed as learning-srs. The quiz dashboard shows a bar chart of the box distribution so progress is visible at a glance.
Static Content Sections
Below the interactive tabs, three static sections provide context. The Key Principles section renders 6 cards covering learning science fundamentals — retrieval practice, spaced repetition, interleaving, prerequisite ordering, desirable difficulty, and system-over-willpower. Each principle cites the underlying research finding (e.g., "Testing yourself is 2-3x more effective than re-reading").
The Math Roadmap section shows a prerequisite-respecting path from Calculus II (current) through Linear Algebra, Multivariable Calculus, Differential Equations, and into Probability/Statistics and Real Analysis. Each node has a status indicator (current, next, future) and a one-line description of what it covers.
The Reading List section features 5 works: Skycak's The Math Academy Way, Bloom's 2 Sigma Problem, Dunlosky's meta-analysis of learning techniques, Ericsson on deliberate practice, and Brown/Roediger/McDaniel's Make It Stick.
The Data Pipeline
The 10,800+ notes displayed on the page are produced by automated heartbeat tasks running on a local GPU. A knowledge seeder task runs twice daily (14:00 and 01:00), generating atomic notes from research feeds. A weekly deep-dive task produces longer-form notes on Saturdays. A knowledge analyst task (running on Opus) reviews the accumulated notes daily, identifying gaps and suggesting new topics. The build script processes vault Markdown files into the JSON format the component consumes, splitting public metadata from private content that gets encrypted.
The result is a page where the content grows autonomously — the learning engine adds roughly 50-100 notes per week without manual intervention — while the frontend remains a static React component reading from two JSON files.