Skip to content

bitpshr/moonbeam

Repository files navigation

Moonbeam icon

MOONBEAM

Tap the letters. Sound out the words. Collect the stars!

A gamified phonics and reading game for kids (ages 3-6) — built to explore modern full-stack TypeScript architecture with a focus on clean patterns, animation, and delightful UX. Not intended for production use.

Next.js TypeScript Tailwind CSS Motion Vitest


Features

  • Letter-by-letter sounding: Tap colorful tiles or use arrow keys to activate each letter left-to-right, with rising-pitch audio feedback
  • 10 progressive levels: From 2-letter words (at, it) to 5-letter blends and digraphs (smile, crane)
  • Connected word animation: All letters activate → tiles unify in color, a glowing border wraps them, and the moon mascot celebrates
  • Fill-up progress button: Fills as letters are selected, turns green and bounces when complete
  • Animated mascot: Inline SVG crescent moon with expressions — idle float, happy shake, celebrating spin with sparkles
  • Star rewards & confetti: Each word earns a star; completing 8 words triggers a level-complete celebration with particle effects
  • Web Audio sounds: Synthesized tones for letter activation, word completion, and level celebration — no audio files
  • Persistent progress: Levels stay unlocked across refreshes via localStorage

Getting Started

Prerequisites

Setup

git clone https://github.com/yourusername/moonbeam.git
cd moonbeam
bun install
bun dev

Open http://localhost:3000.

Other commands

bun run test         # run all 50 unit tests (Vitest + jsdom)
bun run test:watch   # run tests in watch mode
bun run test:ui      # open Vitest UI in browser
bun run type-check   # TypeScript strict check
bun run lint         # ESLint
bun run build        # production build

Architecture

Stack decisions

Concern Choice Why
Framework Next.js 16 App Router Minimal server component shell, client-side game logic
Animation Motion (framer-motion v12) Spring physics for tile bounces, staggered reveals, mascot expressions
Styling Tailwind CSS v4 CSS-based @theme inline config, no config file to maintain
Audio Web Audio API Synthesized tones — zero audio file downloads
Persistence localStorage Zero server-side state, statically exportable
Font Fredoka (Google Fonts) Rounded, variable-weight, designed for children's readability
Testing Vitest + Testing Library Jest-compatible API, Vite-native speed

Data flow

Home (Server Component)
  → Play link → /play (Server Component shell)
    → GameShell (Client Component, useReducer)
      → LevelSelect | WordDisplay | LevelComplete (screen routing)

User taps a letter tile
  → ACTIVATE_NEXT action → reducer updates activatedCount
  → playLetterSound(index) → Web Audio tone
  → LetterTile animates to active state

All letters activated
  → tiles unify in color, border wraps word
  → "I got it!" button bounces → user taps
  → playWordComplete() → NEXT_WORD action
  → 8/8 words → LEVEL_COMPLETE → celebration + confetti

Progress saved to localStorage on level completion

Project structure

moonbeam/
├── app/
│   ├── layout.tsx              # Root: Fredoka font, metadata
│   ├── page.tsx                # Home screen (server component)
│   ├── globals.css             # Tailwind v4 theme, keyframes
│   └── play/
│       └── page.tsx            # Thin wrapper → GameShell
├── components/
│   ├── GameShell.tsx           # Orchestrator (useReducer + localStorage sync)
│   ├── LetterTile.tsx          # Animated letter button (Motion spring)
│   ├── WordDisplay.tsx         # Row of tiles + keyboard handler + fill button
│   ├── LevelSelect.tsx         # 10-level grid with colored badges
│   ├── LevelComplete.tsx       # Celebration overlay with confetti
│   ├── ProgressBar.tsx         # Star progress in frosted pill
│   ├── Mascot.tsx              # Moon SVG with mood expressions
│   └── StarBurst.tsx           # Confetti particle effect
├── lib/
│   ├── types.ts                # All types, constants, color palettes
│   ├── words.ts                # Static word data (10 levels, 8 words each)
│   ├── progress.ts             # localStorage read/write with validation
│   ├── sounds.ts               # Web Audio synthesizer (letter, word, level sounds)
│   └── utils.ts                # cn() utility
└── __tests__/                  # Mirrors source structure
    ├── lib/                    # words, progress
    └── components/             # LetterTile, WordDisplay, LevelSelect, ProgressBar, GameShell

Design decisions worth noting

useReducer over useState. Game state has multiple interdependent fields (level, word index, activation count, completion set). A pure reducer function keeps transitions atomic and testable outside React.

No database. Word lists are static data. Progress lives in localStorage. Zero server-side state means the entire app can be statically exported.

Motion for complex animations. Spring physics for tile bounces, staggered star reveals, and mascot expressions. CSS handles simpler transitions (hover states, gap transitions).

Web Audio over audio files. Synthesized tones using the Web Audio API — rising C-major scale for letter sounds, ascending arpeggios for word completion, and a sparkly melody for level celebration. Zero file downloads, instant playback.

Inline styles for dynamic colors. Tailwind can't detect dynamically interpolated class names (bg-${var}), so tile colors use inline style={{ backgroundColor }} with hex values from a constant array.

White background, no dark mode. This is a kids' app — a clean white background with vibrant pastel tiles is always appropriate. No theme switching complexity.

Fredoka font. A rounded, variable-weight Google Font specifically designed for readability in children's contexts.


Roadmap

  • Pronunciation audio clips per letter using Web Speech API
  • Drag-to-reorder mode for scrambled words
  • Parent dashboard with progress tracking charts
  • Haptic feedback on mobile via Vibration API
  • PWA support for offline play

About

Phonetics game for tiny readers

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors