MindMaze: Building a Simple Yet Smart Aptitude Quiz App

Maithri MedaMaithri Meda
5 min read

MindMaze wasn’t born out of a grand vision. It started with a simple idea:
"Wouldn’t it be cool if there was a clean, offline-friendly quiz app that actually felt nice to use?"

I wanted something that focused on real learning -not leaderboards or gamified fluff. Just category-based MCQs, clean performance tracking, and a UI that didn’t make me cry. So I decided to build it myself.

Spoiler alert: it did not go as smoothly as I thought.
But I learned a ton. From managing quiz state and session tracking to building analytics dashboards and dealing with the mess that is localStorage.

This blog walks through how I built MindMaze, what went wrong (and right), and why I think projects like this are worth doing, especially if you're trying to grow as a developer.

The Goal

MindMaze had a few core goals:

  • Let users take quizzes in Quantitative, Logical, and Verbal categories.

  • Track stats like accuracy, time per question, and performance by category.

  • Persist everything in the browser i.e. no backend.

  • Be minimal but nice to look at. Clean UI, smooth transitions, readable font sizes.

  • Build the whole thing using React + TypeScript + Tailwind CSS (just the stack I’m comfortable with).

The Stack

Here’s what powers MindMaze:

  • Frontend: React + Vite + TypeScript

  • Styling: Tailwind CSS + shadcn/ui + custom gradients

  • Icons: lucide-react

  • State: React Context (for user), custom hooks (for quiz logic)

  • Data: Static questions.json file for MCQs

  • Storage: LocalStorage for everything -users, stats, quizzes

No database, no auth, no cloud functions just front-end logic done well.


How It Works (A Walkthrough)

1. Category & Quiz Selection

When the user lands on /quiz, they’re prompted to choose a category:

  • Quantitative Aptitude

  • Logical Reasoning

  • Verbal Ability

Once selected, they choose how many questions they want and how much time they want to spend. This creates a session object managed by a custom hook called useQuizEngine.

// QuizSetup.tsx
<QuizSetup
  category="logical"
  questionCount={10}
  timeLimit={600}
/>

We store the selected category in localStorage just to persist context across reloads.


2. Quiz Engine + Timer

The core of the app is in useQuizEngine.ts. It handles:

  • Shuffling and selecting questions from questions.json

  • Saving user answers

  • Moving between questions

  • Submitting the quiz

  • Tracking total time and per-question time

Everything is stored in memory while the quiz runs. Once submitted, the data is sent to the user context to update stats.


3. Updating Stats

Stats are where things get interesting. Each user has a full stats object: For example-

{
  totalQuizzes: 2,
  totalQuestions: 15,
  correctAnswers: 9,
  averageAccuracy: 60,
  averageTime: "1:12",
  categoryStats: {
    verbal: { solved: 5, accuracy: 40, avgTime: "0:09" },
    logical: { solved: 10, accuracy: 70, avgTime: "2:55" },
    ...
  }
}

Each quiz submission triggers an updateUserStats() function. It calculates:

  • New average accuracy

  • Weighted average time

  • Per-category stats

  • Recently attempted quizzes

To avoid duplicate updates, I track a unique quiz hash (category_numQuestions_numCorrect_totalTime) and store it in a processedQuizzes Set.

if (processedQuizzes.has(quizId)) {
  console.log("Quiz already processed. Skipping.");
  return;
}

4. The Aptitude DNA (Analytics Dashboard)

After every quiz, users see a dashboard showing:

  • Level and XP (based on quizzes completed)

  • Category-wise performance

  • Recent quiz history

  • Achievements (like "First Quiz Completed" or "Perfect Score")

Each panel is powered by reusable components (StatPanel, MindProfileCard, etc.) with a soft gradient aesthetic. Simple animations and icons make it more engaging without clutter.


5. Achievements (Yes, I Caved)

At first, I didn’t plan to include achievements. Then I did. Then I broke everything. Then I fixed it.

The final version adds achievements based on:

  • First quiz

  • 80%+ accuracy overall

  • Perfect score

  • 50+ correct answers

  • 10+ quizzes completed

If the user has none, we show the criteria instead — so it still feels motivating without being empty.


Example Quiz Flow

Here’s how a typical user flow looks:

  1. User selects “Verbal Ability” → chooses 5 questions, 5 minutes

  2. Quiz begins → questions show one by one, with timer and navigation

  3. User submits → score is calculated

  4. Stats are updated → 40% accuracy, 0:09 avg time

  5. Analytics dashboard shows insights

  6. User goes again — this time Logical, 10 questions

  7. Stats evolve — accuracy increases, XP grows, achievements unlock

  8. User starts seeing patterns in their own aptitude profile

Everything happens on the frontend. No login, no API calls, no server latency. Just a personal learning loop.


What Didn’t Work

This was not a walk in the park.

  • Stat inflation: I updated user stats every render, which inflated quiz counts until I fixed it with a hasUpdatedStatsRef.

  • Achievements crash: One undefined.includes() later, the whole app crashed. Lesson learned: always check your types.

  • Offline support: I tried to make it a PWA. It mostly works —- but caching dynamic session data was messy. That’s a story for another day.


What I Learned

  1. Frontend apps can do more than we think — With just React and localStorage, we can create meaningful, persistent learning tools.

  2. State management matters — The difference between a janky and smooth quiz app is often in how you manage transitions, resets, and side effects.

  3. Small projects teach a lot — This project taught me more about polish and UX than any tutorial ever could.


What’s Next?

I’m planning to:

  • Add more question types (drag/drop, grid logic)

  • Improve accessibility (keyboard nav, screen reader support)

  • Enable true offline mode with IndexedDB and SW caching

  • Add progress sync (in case I do add auth later)


Wrapping Up

MindMaze isn’t perfect. But it’s real. It works. And more than anything — I learned a lot by building it.

I enjoy building full-stack web apps that feel smooth and thoughtful.
I use TypeScript (willingly), and I pay attention to user experience, edge cases, and the little things.

Sometimes that means writing logic for quiz state...
Other times, it means obsessing over a 2px box shadow!


If you’d like to check out the project:

🔗 Live Demo
💻 GitHub Repo

Thanks for reading!!! 💫

0
Subscribe to my newsletter

Read articles from Maithri Meda directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Maithri Meda
Maithri Meda

I'm Maithri. I'm presently in my final year of my bachelors degree in technology. I enjoy building, making cool tech apps and sites that have a purpose and serve in helping and making our everyday lives a bit more exciting. Other than that, I enjoy travelling, singing, cooking, working out and cycling as well. I love reading novels and watching films. I am particularly a fan of fantasy, horror and scientific fiction books. My interests led me to start a blog and to share about my perspective of things. I do like to write, so, I thought of leading in like-minded individuals into this environment to explore and make sense of our interests.