Skip to content

VMotta1/Lyric2Lang

Repository files navigation

This is a Next.js project bootstrapped with create-next-app.

Getting Started

First, run the development server:

npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev

Open http://localhost:3000 with your browser to see the result.

You can start editing the page by modifying app/page.tsx. The page auto-updates as you edit the file.

This project uses next/font to automatically optimize and load Geist, a new font family for Vercel.

Learn More

To learn more about Next.js, take a look at the following resources:

You can check out the Next.js GitHub repository - your feedback and contributions are welcome!

Deploy on Vercel

The easiest way to deploy your Next.js app is to use the Vercel Platform from the creators of Next.js.

Check out our Next.js deployment documentation for more details.

LyricLang

Learn languages through the music you already love. LyricLang is a Duolingo-style language learning app that syncs real song lyrics with AI-generated exercises — so you practice vocabulary and grammar in the context of music you actually enjoy.


What It Does

  • Plays real YouTube music videos with synced lyrics
  • Pauses at each lyric line and generates a language exercise
  • Four exercise types: word match, sentence translation, fill-in-the-blank, and listening comprehension
  • Every 8th line triggers a Lightning Round — a fast-fire timed quiz
  • Tracks XP, level, streak, hearts, and a leaderboard
  • Apple Music-style lyric display — active line large and bold, cascade fades for upcoming lines
  • Desktop split-screen (player left, lyrics right) and mobile pill layout

Supported songs and languages:

Song Artist Language
Nuevayol Bad Bunny Spanish
Hips Don't Lie Shakira Spanish
Alors on Danse Stromae French
Tout Oublier Angele French
Roar Katy Perry English
Firework Katy Perry English

Tech Stack

Layer Technology
Framework Next.js 16 (App Router, Turbopack)
Language TypeScript
Styling Tailwind CSS v4
Animation Framer Motion v12
State Zustand v5
AI Anthropic Claude (Haiku)
Lyrics lrclib.net API
Video YouTube IFrame API via react-youtube

Getting Started

1. Clone and install

git clone https://github.com/VMotta1/Lyric2Lang.git
cd Lyric2Lang
npm install

2. Add your Anthropic API key

Create a .env.local file in the project root:

ANTHROPIC_API_KEY=sk-ant-...your key here...

Get a key at console.anthropic.com. Without it the app falls back to minimal placeholder exercises.

3. Run the dev server

npm run dev

Open http://localhost:3000.


Project Structure

lyric2lang/
├── app/
│   ├── (auth)/login/         # Login page
│   ├── (main)/
│   │   ├── page.tsx           # Dashboard
│   │   ├── library/           # Song library
│   │   ├── leaderboard/       # Leaderboard
│   │   ├── profile/           # Profile page
│   │   └── learn/[songId]/
│   │       ├── page.tsx       # Song overview
│   │       └── play/page.tsx  # Play screen (main game)
│   ├── api/exercise/          # POST endpoint — calls Claude to generate exercises
│   └── globals.css            # Tailwind v4 theme tokens + keyframes
│
├── components/
│   ├── exercises/
│   │   ├── FillInBlank.tsx
│   │   ├── LightningRound.tsx
│   │   ├── ListeningExercise.tsx
│   │   ├── TranslateSentence.tsx
│   │   └── WordMatch.tsx
│   ├── layout/
│   │   ├── BottomNav.tsx
│   │   └── Navbar.tsx
│   ├── player/
│   │   ├── ExerciseOverlay.tsx  # Slide-up exercise container
│   │   ├── LyricDisplay.tsx     # Apple Music-style lyric cascade
│   │   └── YouTubePlayer.tsx    # YouTube iframe + polling loop
│   └── ui/                      # XPBar, HeartCounter, StreakBadge, etc.
│
├── hooks/
│   └── useGameEngine.ts         # State machine: playing → exercise → feedback → complete
│
├── lib/
│   ├── claude.ts                # Exercise generation + caching + fallback
│   ├── claude-client.ts         # Browser-safe wrapper (calls /api/exercise)
│   ├── claude-prompts.ts        # Per-type prompt templates with song language awareness
│   ├── lrc.ts                   # lrclib.net fetch + LRC parser + lyric line builder
│   ├── store.ts                 # Zustand store (user, XP, hearts, leaderboard)
│   └── xp.ts                   # XP calculation and level math
│
├── data/
│   ├── songs.ts                 # Song definitions (6 demoable + 6 locked)
│   └── fallback-exercises.ts    # Hardcoded exercises used when Claude API is unavailable
│
└── types/
    └── index.ts                 # All shared TypeScript interfaces

How the Game Loop Works

  1. Lyrics loadlrclib.net fetches timestamped lyrics. Falls back to hardcoded timestamps if the API has no data.
  2. Video plays — YouTubePlayer runs a 200ms polling loop watching getCurrentTime().
  3. Line triggers — When playback reaches the midpoint of a lyric line, the video pauses and an exercise loads.
  4. Exercise generates — Claude (Haiku) generates an exercise for that specific lyric line. The result is cached so it never regenerates for the same line in the same session.
  5. User answers — Correct = XP earned + combo builds. Wrong = lose a heart.
  6. Feedback shows — Green/red feedback for 1 second, then video resumes from where it paused.
  7. Session ends — After the last lyric line, a summary shows XP earned, accuracy, and lines practiced.

Exercise Types

Type Description Trigger
Word Match Tap to match 4 song-language words to their translations Lines 0, 4, 8…
Translate Sentence Tap words to build the native-language translation Lines 1, 5, 9…
Fill in the Blank Song lyric with one word missing — pick from 4 options Lines 2, 6, 10…
Listening Hear the lyric, pick the correct translation Lines 3, 7, 11…
Lightning Round 30-second rapid-fire word pairs Every 8th line

All exercises are generated in the song's language. A Spanish song (Bad Bunny) produces Spanish exercises. A French song (Stromae) produces French exercises.


Environment Variables

Variable Required Description
ANTHROPIC_API_KEY Yes Anthropic API key for exercise generation

Deployment

The app is a standard Next.js project and deploys to any Node.js host.

Vercel (recommended):

npx vercel

Add ANTHROPIC_API_KEY as an environment variable in your Vercel project settings.


Key Design Decisions

Single YouTubePlayer instance — The YouTube iframe must stay mounted to keep audio and the polling loop running. On mobile the player is positioned off-screen (fixed; top: -9999px) so it plays in the background while a visual thumbnail pill is shown instead.

Exercise caching — Both the server (lib/claude.ts) and browser (lib/claude-client.ts) cache exercises by ${songId}-${lineIndex}-${type}. Claude is never called twice for the same line in the same session.

Song language in prompts — Every Claude prompt explicitly states Song language: Spanish (or French/English) resolved from song.language in songs.ts. This prevents the model from mixing languages when the user's native language differs from the song language.

React 19 setState safetyuseGameEngine maintains a stateRef mirror so submitAnswer can call updateXP/loseHeart (external Zustand updates) outside the React setState updater, complying with React 19's rule against side effects inside updaters.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors