# Handoff: BrainWave Practice Exam Platform ## Overview BrainWave is a web-based practice exam platform that lets a user upload a JSON file describing an exam and take it interactively. It supports subjects from mathematics (with full LaTeX rendering) to language learning (translation questions) to general knowledge (multiple choice, essays, etc.). Results are scored automatically where possible, explained in a review screen, and persisted locally so users can resume in-progress exams and see a history of past attempts. ## About the Design Files The files in this bundle are **design references created in HTML** — a working prototype showing the intended look, behavior, and data model, not production code to copy directly. The task is to **recreate these HTML designs in the target codebase's existing environment** (React, Vue, Next.js, SvelteKit, native mobile, etc.) using its established patterns, component library, and state-management conventions. If no environment exists yet, pick the framework best-suited to the project and implement the designs there. The prototype is implemented as a single-page React app using in-browser Babel for convenience; production should use a real build pipeline. ## Fidelity **High-fidelity (hifi).** The mocks are pixel-level specifications with final colors, typography, spacing, and interactions. All eight question renderers, the results/review flow, history, persistence, and keyboard shortcuts are implemented and working. Recreate the UI pixel-perfectly using the codebase's existing libraries and patterns. --- ## Screens / Views ### 1. Landing / Upload **Purpose:** User lands here to load an exam. Supports drag-and-drop JSON upload, curated sample exams, resume of in-progress attempt, and past-attempt history. **Layout:** - Max width 1080px, centered; padding `72px 32px 120px`. - Eyebrow label (uppercase monospace, 11px, letter-spacing 0.12em). - H1 title — Fraunces serif, clamp(40px, 6vw, 68px), line-height 1.02, letter-spacing -0.028em. Last two words wrapped in `` and colored `var(--accent)`. - Subtitle paragraph, 17px, max-width 58ch, color `var(--ink-2)`. - **Two-column grid** (1.2fr / 1fr, gap 48px): - Left: Dropzone + error banner + resume card + supported-types list. - Right: "Try a sample" section with 3 sample cards. - Below the grid (when history exists): "Past attempts" list. **Components:** - **Dropzone**: 1.5px dashed border, radius 14px, padding `40px 32px`, background `var(--paper-2)`. On hover/drag-over: border → accent, background → `var(--accent-weak)`. Contains a 40×40 icon (upward arrow inside rounded square), h3 (16px, weight 500), caption (13.5px, `var(--ink-3)`). - **Resume card**: 1px border, radius 10px, padding 16px, `var(--paper-2)` background. Title + subcaption + "Resume →" primary button. - **Sample card**: flex row, gap 16px, 1px border, radius 10px, padding 16px. 36×36 mark tile (serif glyph), title (14.5px, weight 500), meta (12.5px, `var(--ink-3)`), "→" arrow on the right. - **History row**: 4-column grid `1fr auto auto auto`, 14px items separated by 1px bottom borders. Title + timestamp caption, elapsed time (monospace), score pill (pass/fail colored), "Review" ghost button. ### 2. Exam Runner **Purpose:** Take the exam, one question at a time, with a navigator sidebar and metadata rail. **Layout:** 3-column grid `280px 1fr 280px`, full height minus topbar (57px). - **Sidebar (left, sticky):** Exam title (Fraunces serif, 22px) + subtitle + "Questions" section label + nav list + progress bar + Submit/Exit buttons. - **Main (center):** Max-width 920px, padding `48px 64px 120px`. Question header, prompt, media, renderer, optional inline feedback block, footer with nav buttons + keyboard-hints strip. - **Meta rail (right, sticky):** Elapsed, Remaining (if timed), Points possible, Mode, Author — each in a "meta block" with uppercase mono label and Fraunces serif value. **Components:** - **Topbar:** 14px × 28px padding, sticky, 1px bottom border. 22×22 brand mark (1.5px border square with inset accent), brand name "BrainWave" (weight 600, -0.02em), faint "/ practice" qualifier. Right side: current exam title + Exit button. - **Nav item:** 3-column grid `28px 1fr auto`, padding `7px 10px`, radius 6px. Mono 2-digit number + category/type title + 7×7 status dot. Dot colors: `var(--line-2)` (blank), `var(--accent)` (answered), `var(--warn)` (flagged), `var(--correct)` (correct in immediate mode), `var(--wrong)` (wrong in immediate mode). - **Question header:** flex row, 16px gap, 32px bottom margin, 24px padding-bottom, 1px bottom border. Mono "Question 01 / 07" + category chip (12px, mono, `var(--paper-3)` bg, 4px radius, 2×8 padding) + right-aligned points label. - **Question prompt:** Fraunces serif, 26px, line-height 1.35, -0.015em, weight 400. Renders LaTeX inline. - **Question footer:** flex row, 48px top margin, 32px padding-top, 1px top border. Previous / Flag / (Check answer) / Next or Submit buttons. Spacer between middle and right groups. ### 3. Question Renderers (8 types) All renderers share these hooks: `value` (current answer), `onChange(next)`, `locked` (read-only), `graded` (show correctness coloring). **multiple-choice / multiple-select:** - Vertical list of `.choice` buttons. 1px border, radius 10px, padding `16px 20px`, 15px text, line-height 1.5. - 22×22 round marker (square for multi-select), 1.5px border. - When selected: marker fills with `var(--ink)`; inner 8px dot (or checkmark for square). - Mono "choice-key" (A–D) between marker and text. - Graded-correct: border & bg → `var(--correct)` / `var(--correct-weak)`. Graded-wrong: `var(--wrong)` / `var(--wrong-weak)`. **short-answer / translation:** - Single `` — 100% width, padding `10px 12px`, 1px border, radius 10px. Focus: border → accent, 3px focus ring. - For translation: subtitle "Answer in {targetLanguage}" in faint mono, 11px. **math-input:** - Monospace input + "Preview" block underneath showing live KaTeX render of the LaTeX the user types. - Preview block: `var(--paper-2)` bg, 1px border, radius 10px, padding `14px 16px`, min-height 48px, left-aligned mono uppercase label + rendered output. **essay:** - Textarea, min-height 120px, 16px padding, radius 10px. - Below: word count + "Self-graded · see rubric on review". If `q.minWords` set and below threshold, word count is colored `var(--wrong)`. **match:** - 2-column grid, 32px gap. Left = "Items", right = "Matches". - Click a left item → activates it (`var(--accent)` border + 3px accent-weak ring). Click a right item → creates pairing; paired items show a small badge with the other side's index letter/number. - Click paired left to clear it; click paired right to clear pairing. **order:** - Draggable list. Each item: 14×16 padding, 1px border, radius 10px. Shows `⋮⋮` handle + mono position number + text + up/down buttons (ghost, small). - While dragging: opacity 0.4. Drop target highlighted with accent-colored top or bottom border. - Initial order is a deterministic shuffle seeded from the question id. ### 4. Results / Review **Purpose:** Summary of performance + per-category breakdown + detailed review of every question. **Layout:** Max-width 960px, centered, padding `64px 32px 120px`. - Eyebrow label → "Exam complete · {title}" (or "Reviewing past attempt · ..."). - H1 title — Fraunces, 56px, -0.025em, line-height 1.05. "You scored {pct}%" with pct in accent. Subline in 0.5em size, `var(--ink-3)`, announces pass/fail against `passingScore` (default 60). - **Score grid:** 3 equal columns (`1fr 1fr 1fr`), 1px top and bottom borders with internal 1px separators. Each cell: uppercase mono label + Fraunces value (48px) + mono unit suffix. - **Category breakdown** (if more than one category): 3-col grid rows `180px 1fr 60px` — label + 4px bar + right-aligned percent. - **Review list:** Collapsible items, 1px border, radius 10px, 16px margin-between. Header: mono number + truncated prompt + status pill (correct/wrong/ungraded) + +/− toggle. Open body: re-renders full question with `locked graded`, shows explanation and rubric. - Footer buttons: Retake exam (primary) + Back to home (ghost). ### 5. Tweaks Panel (floating) Fixed bottom-right, 280px wide, 1px border, 10px radius, `var(--shadow-md)`. - Header: uppercase mono "Tweaks" + close button. - Body rows: each row has a mono label + segmented control (`.tweak-control` background with pill-selected active button). - Controls: Theme (Light/Dark), Text size (S/M/L), Feedback (Auto/Immediate/End). --- ## Interactions & Behavior ### Upload - File input accepts `application/json`. - On drop or select: read file → `JSON.parse` → `validateExam()` → `loadExam()`. - `validateExam` checks for `title`, non-empty `questions` array, and every question having `id`, `type`, `prompt`. - Error banner renders in `var(--wrong-weak)` with `var(--wrong)` border for 1px/8px radius. ### Exam flow - On load, state initializes `{ currentIdx: 0, answers: {}, flags: {}, revealed: {}, startedAt: Date.now(), feedbackMode }`. - `feedbackMode` resolves: if Tweak is "auto", use `exam.feedbackMode` (default "end"); otherwise use Tweak override. - Every state change `saveState({exam,state})` to localStorage under `brainwave.exam.state`. - Timer (`exam.timeLimitMinutes`): counts down from `timeLimitMinutes*60_000 - elapsed`. Last 60s: value colored `var(--wrong)`. At 0: auto-submit. - Submit: compute graded snapshot, append to `brainwave.exam.history` (capped 30 entries), clear active-state key, advance to Results. ### Grading - **multiple-choice**: user answer === `q.answer` (string id). - **multiple-select**: unordered array equality. - **short-answer / translation**: normalize both using `{caseSensitive, ignorePunctuation, ignoreAccents}` options, then compare against `[answer, ...acceptedForms]`. - **math-input**: strip whitespace, `\left/\right`, `\,`, braces around single chars, lowercase — then exact match against accepted forms. - **match**: every key in `q.answer` must have matching user pairing. - **order**: ordered array equality. - **essay**: ungraded by default; optional `selfGrade` (0–1) yields partial points. ### Keyboard - `←`/`k`: previous question. - `→`/`j`: next question. - `f`: toggle flag. - `1`–`9`: select choice for multiple-choice questions. - Disabled when focus is inside ``/`