Piano Hero is a Guitar Hero-inspired rhythm game built for piano. Players must hit falling notes at the correct timing to score points and build combos. The game features a built-in song editor for creating custom songs and supports audio synchronization.
๐ฎ Play Online
Piano.Hero.-.Google.Chrome.2025-08-03.22-09-05.mp4
WhatsApp.Video.2025-08-03.at.22.31.45.mp4
WhatsApp.Video.2025-08-03.at.22.32.36.mp4
- Frontend: React 18 with TypeScript
- Build Tool: Vite (fast HMR and optimized builds)
- UI Framework: Material-UI (MUI) v5 - Complete component library
- Audio Processing: WaveSurfer.js v7 - Advanced audio waveform visualization and playback
- Graphics: Native HTML5 Canvas - Custom implementation for high-performance rendering
The application uses React Context API with three specialized contexts:
GameContext(src/context/GameContext.tsx) - Manages game state, scoring, and lifecycleSongEditorContext(src/context/SongEditorContext.tsx) - Handles song creation and editingSongFileHandlerContext(src/context/SongFileHandlerContext.tsx) - Manages file operations
Component: src/components/PianoCanvas/index.tsx
- Custom Canvas Engine: Built from scratch using HTML5 Canvas API
- Visual Piano: Renders white and black keys with proper proportions
- Real-time Interaction: Mouse clicks and keyboard inputs trigger notes
- Visual Feedback: Keys light up when pressed with timing-based colors
Key Functions:
drawCanvas()- Main rendering loop insrc/components/PianoCanvas/utils.tsfindNearestKeyAndMinDistance()- Click-to-key mappingplayNoteAudio()- Audio playback with caching
Implementation: src/components/PianoCanvas/index.tsx + src/components/PianoCanvas/utils.ts
- Smooth Animation: RequestAnimationFrame-based note movement
- Collision Detection: Custom algorithm for note-key intersection
- Visual Design: Notes fall towards piano keys with proper scaling
- Multi-note Support: Handles chords and complex patterns
Core Constants (src/components/PianoCanvas/constants.ts):
CANVAS_HEIGHT_DEFAULT: 600px canvas heightPIANO_HEIGHT: 150px piano sectionLOOKAHEAD_TIME: 3 seconds of visible notesWHITE_KEY_WIDTH: Key sizing calculations
Component: src/engine/RhythmEngine.ts
Advanced timing-based scoring system with multiple judgment levels:
- Perfect: ยฑ0.2s (highest points)
- Great: ยฑ0.3s
- Good: ยฑ0.4s
- Hit: Within timing windows
- Miss: Outside timing windows
Features:
- Combo System: Tracks consecutive hits with multipliers
- Progress Tracking: Real-time completion percentage
- Timing Windows: Configurable early/late tolerances
- Key Indexing: Optimized note lookup per piano key
Component: src/components/SongEditor/index.tsx
Full-featured song creation tool with multiple sub-components:
SongInformation- Set song metadata (name, artist, duration)AudioUpload- Import background audio filesInteractiveGamePreview- Real-time preview with playbackNoteSelection- Choose which notes to placeNotesList- View and edit all song notesExportControls- Export songs as JSONEditNoteDialog- Fine-tune note timing and duration
Editing Features:
- Drag & Drop: Move notes by dragging on canvas
- Duration Control: Resize notes by dragging bottom edge
- Click Placement: Click piano keys to add notes
- Audio Sync: Synchronize with background music
Components: Multiple files handling different aspects
Audio Sources:
- Individual Notes:
public/sounds/- All piano notes (C1-C8, including sharps/flats) - Background Music: User-uploaded files via
src/components/SongEditor/components/AudioUpload/ - Audio Caching: Optimized loading in
src/components/PianoCanvas/index.tsx
WaveSurfer Integration:
- Visual waveform display in song editor
- Precise audio synchronization
- Real-time playback control
Component: src/components/GameController/index.tsx
Manages game flow through five distinct states:
- MENU (
src/components/GameController/components/Stages/Menu/) - Song selection - LOADING (
src/components/GameController/components/Stages/Loading/) - Asset loading - PLAYING (
src/components/GameController/components/Stages/Play/) - Active gameplay - PAUSED (
src/components/GameController/components/Stages/Pause/) - Game paused - ENDED (
src/components/GameController/components/Stages/EndGame/) - Results screen - SONG_EDITOR - Song creation mode
Implementation: Throughout src/context/GameContext.tsx
- Real-time Accuracy: Calculated as (correct notes / total notes) ร 100
- Combo Counter: Tracks consecutive hits, resets on miss
- Score System: Points awarded based on timing accuracy
- Progress Bar: Visual completion indicator
The game operates on a precise timing system using performance.now() for millisecond accuracy:
Time Management (src/components/GameController/index.tsx):
const start = performance.now() - currentTime * 1000;
const step = (ts: number) => {
actions.setCurrentTime((ts - start) / 1000);
animationRef.current = requestAnimationFrame(step);
};Core Physics (src/components/PianoCanvas/utils.ts):
The falling notes use a sophisticated position calculation:
const timeUntilNote = noteStartTime - currentTime;
const fallProgress = (LOOKAHEAD_TIME - timeUntilNote) / LOOKAHEAD_TIME;
const fallAreaHeight = noteAreaHeight - NOTE_AREA_BOTTOM_PADDING;
const noteCenterY = fallProgress * fallAreaHeight + NOTE_AREA_TOP_PADDING;How it works:
LOOKAHEAD_TIME= 4 seconds - notes become visible 4 seconds before they should be hitfallProgressranges from 0 (note appears) to 1 (note reaches piano)- Position mapping: Linear interpolation between top of canvas and piano keys
- Real-time updates: 60fps via
requestAnimationFrame
Rhythm Engine (src/engine/RhythmEngine.ts):
The game uses a sophisticated multi-tier timing system:
// Timing judgments (in seconds):
if (delta >= 0 && delta <= 0.2) judgement = "perfect"; // 300 points
else if (absDelta <= 0.3) judgement = "great"; // 200 points
else if (absDelta <= 0.4) judgement = "good"; // 100 points
else if (delta >= -early && delta <= late) judgement = "hit"; // 50 points
else judgement = "miss"; // 0 pointsPer-Key Indexing: The engine maintains separate note queues for each piano key for optimal performance:
Map<string, number[]>- Maps each key to its note indicesMap<string, number>- Tracks next unprocessed note per key- Prevents double-hits and optimizes lookup time
Multi-Layer Rendering (src/components/PianoCanvas/utils.ts):
- Background Layer: Canvas background + piano strip
- Note Layer: Falling notes with collision shapes
- Piano Layer: Interactive keys with hit feedback
- UI Layer: Score feedback and labels
Optimized Rendering:
- Viewport Culling: Only renders visible notes
- Partial Redraws: Piano keys redraw separately via
redrawPianoStrip() - Color-Coded Feedback: Instant visual feedback based on timing accuracy
// Note visibility optimization
const noteIsVisible = currentTime >= noteStartTime - LOOKAHEAD_TIME &&
currentTime <= noteEndTime + 1;
const noteIsInViewport = noteCenterY >= -NOTE_AREA_BOTTOM_PADDING &&
noteCenterY <= height;Keyboard Layout (src/utils/constants.ts):
- 88 Piano Keys mapped to computer keyboard
- White Keys: Letters (Q,W,E,R,T,Y,U,I,O,P, etc.)
- Black Keys: Numbers (2,3,5,6,7, etc.)
- Offset System: Each key has a precise visual offset for proper spacing
Audio Architecture:
- Individual Note Sounds: 88 separate MP3 files in
/public/sounds/ - Audio Caching:
Map<string, HTMLAudioElement>prevents reload delays - Background Audio Sync: WaveSurfer.js provides precision audio timing
- Smart Audio Mixing: Piano sounds only play for wrong notes when background audio is active
State Transitions (src/context/GameContext.tsx):
MENU โ LOADING โ PLAYING โ PAUSED โ ENDED
โ โ
SONG_EDITOR โโ โโ โโ โโ โโ โโ โโ โโ โโ โโ
State Management: Each state has specific logic:
- PLAYING: Active game loop, timing engine, collision detection
- PAUSED: Suspends timing, preserves state
- ENDED: Score calculation, progress tracking
Real-time Score Calculation:
// Accuracy: (correct / total) * 100
const accuracy = totalNotes > 0 ? (correctNotes / totalNotes) * 100 : 0;
// Combo Logic: Resets on wrong/miss, increments on correct
if (score.wrongNotes > prevScore.wrongNotes) setCombo(0);
else if (score.correctNotes > prevScore.correctNotes) {
setCombo(prevCombo => {
const newCombo = prevCombo + 1;
setMaxCombo(prevMax => Math.max(prevMax, newCombo));
return newCombo;
});
}Interactive Note Editing:
- Drag & Drop: Converts mouse Y-position to time using
getTimeFromY() - Duration Editing: Bottom-edge dragging adjusts note length
- Real-time Preview: Instant visual feedback during editing
- Audio Synchronization: WaveSurfer provides waveform visualization
Data Flow:
User Input โ Canvas Coordinates โ Time Conversion โ Note Update โ Re-render
Rendering Optimizations:
- Selective Redraws: Only piano strip updates for key presses
- Object Pooling: Reuses canvas contexts and audio elements
- Viewport Culling: Skips off-screen note calculations
- Efficient Hit Detection: Spatial partitioning for note lookups
Memory Management:
- Audio Caching: Prevents repeated file loads
- Context Cleanup: Proper cleanup of timers and event listeners
- Component Memoization: Reduces unnecessary React re-renders
Note Position Formula:
Y = fallProgress ร (canvasHeight - pianoHeight - padding) + topPadding
fallProgress = (lookaheadTime - timeUntilNote) / lookaheadTime
timeUntilNote = noteStartTime - currentGameTime
Timing Accuracy:
delta = userInputTime - noteStartTime
judgement = f(|delta|, timingWindows)
points = judgementMap[judgement].points
src/
โโโ components/
โ โโโ GameArea/ # Main game container
โ โโโ GameController/ # Game state management & stages
โ โโโ Header/ # Application header
โ โโโ PianoCanvas/ # Core piano rendering & interaction
โ โโโ SongEditor/ # Song creation tools
โโโ context/ # React Context providers
โ โโโ GameContext.tsx # Game state & scoring
โ โโโ SongEditorContext.tsx # Song editing state
โ โโโ SongFileHandlerContext.tsx # File operations
โโโ engine/
โ โโโ RhythmEngine.ts # Core game logic & timing
โ โโโ types.ts # Game engine types
โ โโโ constants.ts # Timing configurations
โโโ utils/
โ โโโ constants.ts # Piano notes & mappings
โ โโโ interfaces.ts # Type definitions
โ โโโ songLibrary.ts # Song management
โ โโโ time.ts # Time utilities
โโโ songs/ # Predefined songs
- Node.js โฅ20
- Yarn package manager
# Clone repository
git clone https://github.com/KozielGPC/piano-hero.git
# Enter directory
cd piano-hero
# Install dependencies
yarn install
# Start development server
yarn dev
# Build for production
yarn build
# Preview production build
yarn previewyarn dev- Start development server with HMRyarn build- TypeScript compilation + production buildyarn lint- ESLint code quality checkyarn preview- Preview production build locally
- Interstellar Main Theme - Hans Zimmer (simplified)
- Custom Songs - Import JSON files or create in the song editor
Each piano key maps to a computer keyboard key:
- White Keys: Letters (A, S, D, F, G, H, J, etc.)
- Black Keys: Numbers and symbols
- Full mapping: Defined in
src/utils/constants.ts
- Click Piano Keys: Play individual notes
- Click Notes: Select/edit notes in song editor
- Drag Notes: Move timing or adjust duration
- Canvas Interaction: Add notes in editor mode
- Canvas Rendering: Optimized redraw cycles, only updates changed regions
- Audio Caching: Preloads and caches all piano note sounds
- RequestAnimationFrame: Smooth 60fps animation loops
- Component Memoization: Prevents unnecessary re-renders
- High Precision: Uses
performance.now()for millisecond accuracy - Audio Sync: Synchronizes visual elements with audio playback
- Configurable Windows: Adjustable timing tolerances per difficulty
Songs are stored as JSON with this structure:
{
"name": "Song Name",
"artist": "Artist Name",
"duration": 180,
"notes": [
{
"note": "C4",
"time": 1.5,
"duration": 0.5,
"type": "white"
}
]
}- โ Interactive piano with full keyboard
- โ Falling notes with smooth animation
- โ Advanced scoring system (Perfect/Great/Good/Hit/Miss)
- โ Combo system with visual feedback
- โ Song editor with audio synchronization
- โ JSON song import/export
- โ Audio file upload support
- โ Real-time game preview
- โ Drag-and-drop note editing
- โ Multiple game states (Menu/Play/Pause/End)
- โ Progress tracking and accuracy calculation
- ๐ฏ Difficulty levels (Easy/Medium/Hard)
- ๐ Leaderboards and score persistence
- ๐ผ Auto-generation from MP3 files
- ๐ Multiplayer gameplay
- ๐ฑ Mobile device support
- ๐จ Visual themes and customization
- ๐ Sound effects and haptic feedback
Contributions are welcome! Feel free to:
- ๐ Report bugs via GitHub Issues
- ๐ก Suggest features and improvements
- ๐ง Submit Pull Requests
- ๐ Improve documentation
- ๐ต Create and share songs
This project is open source. Feel free to use, modify, and distribute according to the repository license.