Skip to content

DareDev256/typemaster-template

Repository files navigation

TypeMaster Template

A customizable typing game for learning any topic. Fork this template and populate it with your own curriculum - medical terms, language vocabulary, coding shortcuts, or anything else you want to learn by typing.

TypeMaster Screenshot TypeScript Tailwind CSS

Features

  • Retro Arcade Theme - 8-bit pixel art aesthetic with neon colors
  • Multiple Game Modes - Quiz mode and timed race mode
  • Smart Task Selection - Category-balanced algorithm ensures chapter diversity and difficulty mix
  • Progress Tracking - XP system, levels, and streaks saved locally (shared via React context, syncs across tabs)
  • Study Mode - Review concepts before playing
  • AI Challenge (Optional) - OpenAI-powered quiz generation
  • Shortcut Hints Overlay - Contextual keyboard shortcut hints for new users, auto-dismisses on first keystroke
  • Sound Effects - Procedural 8-bit audio
  • Mobile Friendly - Responsive design works on all devices
  • 100% Customizable - Change curriculum, branding, and features via JSON

Quick Start

# Clone the template
git clone https://github.com/YOUR_USERNAME/typemaster-template.git my-typing-game
cd my-typing-game

# Install dependencies
npm install

# Start development server
npm run dev

Open http://localhost:3000 to see your game.

Customizing Your Game

1. Site Branding (curriculum/config.json)

Edit the main config file to customize your game:

{
  "siteName": "MedTerms",
  "tagline": "Learn medical terminology by typing",
  "description": "Master medical vocabulary with this typing game",
  "theme": {
    "primary": "#00FF9F",
    "secondary": "#00D4FF",
    "accent": "#FF6B9D"
  },
  "features": {
    "soundEffects": true,
    "studyMode": true,
    "aiChallenge": true,
    "leaderboard": true
  },
  "gameModes": {
    "quiz": {
      "enabled": true,
      "description": "Type the term that matches the definition"
    },
    "race": {
      "enabled": true,
      "duration": 60,
      "description": "Type as many terms as possible in 60 seconds"
    }
  }
}

2. Adding Chapters

Create a new JSON file in curriculum/chapters/:

{
  "id": "anatomy-basics",
  "title": "Anatomy Basics",
  "description": "Learn the fundamental parts of the human body",
  "icon": "ai-foundations",
  "order": 1,
  "concepts": [
    {
      "id": "anat-001",
      "term": "femur",
      "definition": "The thigh bone, longest bone in the human body",
      "difficulty": "easy"
    },
    {
      "id": "anat-002",
      "term": "patella",
      "definition": "The kneecap, a small bone protecting the knee joint",
      "difficulty": "medium"
    }
  ],
  "levels": [
    {
      "id": 1,
      "name": "Bones 101",
      "concepts": ["anat-001", "anat-002"],
      "requiredXp": 0,
      "gameMode": "quiz"
    }
  ]
}

Then import it in src/lib/curriculum-loader.ts:

import anatomyBasics from "../../curriculum/chapters/anatomy-basics.json";

const chapterFiles = [
  anatomyBasics,
  // Add more chapters here
];

3. Available Icons

Use any of these built-in icons in your chapter's icon field:

Icon Name Color Best For
ai-foundations Green General learning, intro chapters
full-stack Pink Layered concepts, stacks
machine-learning Yellow Data, analytics
code-practice Lime Programming, code
databases Emerald Storage, data
security-auth Rose Security, passwords
containers-docker Blue DevOps, infrastructure
cloud-platforms Violet Cloud, services

Unknown icon names gracefully fall back to a question mark icon.

Chapter & Concept Schema

Chapter Structure

Field Type Required Description
id string Yes Unique identifier (used in URLs)
title string Yes Display title
description string Yes Short description shown on chapter card
icon string Yes Icon name from built-in set
order number Yes Display order (1, 2, 3...)
concepts array Yes Array of concept objects
levels array Yes Array of level objects

Concept Structure

Field Type Required Description
id string Yes Unique identifier (referenced in levels)
term string Yes The word/phrase to type
definition string Yes The definition shown as a prompt
difficulty string Yes "easy", "medium", or "hard"

Level Structure

Field Type Required Description
id number Yes Level number (1, 2, 3...)
name string Yes Level display name
concepts array Yes Array of concept IDs for this level
requiredXp number Yes XP needed to unlock (0 for first level)
gameMode string Yes "quiz" or "race"

Task Selection Algorithm

TypeMaster uses a category-balanced selection algorithm (diversePick() in src/utils/task.ts) instead of naive random shuffling. This ensures every round feels varied and challenging:

Guarantee How It Works
Chapter balance Concepts are drawn proportionally via round-robin across all unlocked chapters — no single chapter can dominate a round
Difficulty floor At least 2 hard-difficulty concepts per round (when available), preventing all-easy streaks
True shuffle Final selection uses Fisher-Yates shuffle so presentation order is unpredictable
Graceful fallback If the pool is smaller than the requested count, the entire pool is returned shuffled

Used by Race Mode and AI Explain Mode. Quiz Mode uses level-defined concept lists already curated by the curriculum author.

import { diversePick } from "@/utils/task";

// Pick 10 concepts balanced across chapters, at least 2 hard
const round = diversePick(concepts, 10);

// Custom difficulty floor (at least 3 hard concepts)
const hardRound = diversePick(concepts, 10, 3);

Persistence Engine (src/lib/storage.ts)

All game state lives in localStorage and flows through a single persistence module. Every read is schema-validated — tampered or corrupted data is rejected and reset to safe defaults. Storage keys are auto-namespaced from config.siteName, so multiple TypeMaster instances on the same domain never collide.

API Reference

Function Purpose Returns
getProgress() Read current user state (XP, level, streaks, scores) UserProgress (safe defaults if missing/corrupt)
saveProgress(progress) Write full progress object to localStorage void
updateProgress(partial) Merge partial updates into current state UserProgress
addXP(amount) Award XP and auto-calculate level (XP_PER_LEVEL threshold) UserProgress
completeLevel(chapterId, levelId) Mark a level complete (idempotent — no duplicates) UserProgress
updateConceptScore(id, isCorrect) Track per-concept correct/incorrect counts and last-seen timestamp UserProgress
getConceptsForReview(limit?) Get concepts where incorrect > correct, oldest-first (spaced repetition) string[]
updateStreak() Increment if played yesterday, reset if gap, hold if same day UserProgress
resetProgress() Clear all saved state (progress + last-played date) void

Key Design Decisions

  • SSR safety — Every function guards against typeof window === "undefined", returning safe defaults during Next.js server rendering
  • Schema validationvalidateProgressShape() checks every field type, range, and structure before trusting parsed JSON. This blocks localStorage injection attacks where a malicious script writes unexpected types into the progress key
  • Namespaced keys — Derived from STORAGE_KEYS in src/lib/storage-keys.ts, which prefixes every key with the slugified site name (e.g., typemaster_progress). Fork the template, change siteName, and storage isolation is automatic
  • Immutable updatesupdateProgress() spreads current state with updates, writes, and returns the new state — components always get the post-write value

Usage

import { addXP, completeLevel, getConceptsForReview } from "@/lib/storage";

// Award 50 XP after a correct answer
const updated = addXP(50);
console.log(updated.level); // auto-leveled if XP threshold crossed

// Mark chapter "web-dev" level 3 as complete
completeLevel("web-dev", 3);

// Get struggling concepts for a review session
const weak = getConceptsForReview(5);
// → ["concept-id-1", "concept-id-2"] (oldest mistakes first)

AI Challenge Mode (Optional)

AI Challenge uses OpenAI to generate unique quiz questions based on concepts you've learned. To enable:

  1. Keep features.aiChallenge: true in config.json
  2. Get an OpenAI API key from platform.openai.com
  3. In the game, go to Settings and enter your API key
  4. Your key is stored locally in your browser - never sent to any server except OpenAI

To disable AI Challenge completely, set features.aiChallenge: false in config.json.

Deployment

Vercel (Recommended)

npm install -g vercel
vercel

Other Platforms

This is a standard Next.js 14+ app. Deploy to any platform that supports Next.js:

  • Netlify
  • AWS Amplify
  • Railway
  • Self-hosted with npm run build && npm start

Security

TypeMaster ships with production-grade HTTP security headers configured in next.config.ts:

Header Value Purpose
Content-Security-Policy default-src 'self'; connect-src 'self' https://api.openai.com; ... Primary XSS mitigation — restricts all resource origins
Strict-Transport-Security max-age=31536000; includeSubDomains Forces HTTPS, prevents downgrade attacks
Referrer-Policy strict-origin-when-cross-origin Safe cross-origin requests (fixes YouTube Error 153)
X-Content-Type-Options nosniff Prevents MIME-type sniffing
X-Frame-Options SAMEORIGIN Blocks clickjacking
X-XSS-Protection 1; mode=block Legacy XSS filter
Permissions-Policy camera=(), microphone=(), geolocation=() Minimizes API surface

Defense in depth:

  • API key handling — Keys are validated against the sk- format pattern before storage. OpenAI calls are rate-limited to 10/minute client-side. AI responses are structure-validated before use.
  • Prompt injection guard — Curriculum content is sanitized (dangerous chars stripped, length-capped) before embedding in AI prompts, preventing prompt manipulation via custom curriculum data.
  • localStorage integrity — Progress data is validated against the UserProgress schema on every read. Tampered or corrupted payloads are rejected and reset to safe defaults.
  • Error sanitization — API error messages are filtered before reaching the UI, preventing internal detail leakage.

Tech Stack

  • Next.js 16 - React framework with App Router
  • TypeScript - Type safety
  • Tailwind CSS 4 - Styling (uses @theme inline)
  • Framer Motion - Animations
  • Web Audio API - Procedural 8-bit sounds
  • LocalStorage - Progress persistence (auto-namespaced per instance)

File Structure

typemaster-template/
├── curriculum/
│   ├── config.json              # Site configuration
│   └── chapters/
│       ├── programming-basics.json   # Example chapter
│       └── web-development.json      # Example chapter
├── src/
│   ├── app/                     # Next.js pages
│   ├── components/              # React components
│   ├── data/curriculum.ts       # Re-exports from loader
│   ├── hooks/                   # Custom React hooks
│   ├── lib/
│   │   ├── curriculum-loader.ts # Loads JSON curriculum
│   │   ├── storage-keys.ts      # Namespaced localStorage key registry (collision-safe)
│   │   ├── storage.ts           # Persistence engine — validated reads, XP, streaks, review queue
│   │   └── openai.ts            # Optional AI integration
│   ├── utils/
│   │   ├── task.ts              # diversePick() — category-balanced concept selection
│   │   └── validation.ts        # Shared validation (params, API key, progress)
│   └── types/game.ts            # TypeScript types
├── public/                      # Static assets
└── package.json

Development

# Run dev server
npm run dev

# Type check
npm run lint

# Build for production
npm run build

# Start production server
npm start

Contributing

Contributions welcome! Feel free to:

  • Add new icons to src/components/ui/PixelIcon.tsx
  • Improve the game mechanics
  • Add new features
  • Fix bugs

License

MIT License - feel free to use this for personal or commercial projects.


Made with love. Type your way to mastery!

About

A customizable typing game for learning any topic. Fork and add your own curriculum!

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors