RiffScore is a self-hostable, embeddable sheet music editor for React.
Unlike commercial platforms that require users to leave your site or pay subscription fees, RiffScore allows you to embed interactive, editable scores directly into your application.
npm install riffscoreimport { RiffScore } from 'riffscore';
function App() {
return <RiffScore id="my-editor" />;
}That's it! RiffScore renders a fully interactive grand staff editor with sensible defaults.
<RiffScore id="my-editor" config={{
score: {
staff: 'treble', // 'grand' | 'treble' | 'bass' | 'alto' | 'tenor'
measureCount: 4,
keySignature: 'G'
}
}} />See Configuration for all options.
<RiffScore config={{
ui: { showToolbar: false },
interaction: { isEnabled: false }
}} />See Interaction Configuration for more display modes.
const api = window.riffScore.get('my-editor');
api.select(1) // Select measure 1
.addNote('C4', 'quarter') // Add a quarter note
.addNote('E4') // Add with current duration
.play(); // Play from selectionSee the Cookbook for more recipes.
- Self-Hostable: No external dependencies or platform lock-in.
- Embeddable: Drop it into any React application.
- Configurable: Full control over UI, interactions, and score content.
- SMuFL Compliance: Beautiful engraving using the Bravura font.
- Export Options: JSON, MusicXML, and ABC notation export.
- Theming: Built-in dark, light, cool, and warm themes.
- Imperative Control: Programmatically control the score via
window.riffScore(API Reference) - Fluent Chaining:
api.select(1).addNote('C4').play()— chainable methods for concise scripting. - Event Subscriptions: React to state changes with
api.on('score', callback)andapi.on('batch', callback). - Transaction Batching: Atomic operations with
beginTransaction/commitTransactionfor single undo steps. - Playback API:
play(),pause(),stop(),rewind(),setInstrument()for programmatic audio control.
- Music Theory: Powered by Tonal.js for scales, chords, and transposition.
- Audio Playback: Tone.js sampler with multiple instrument support.
- MIDI Input: Connect a MIDI keyboard for note entry (experimental).
| Mac | Windows | Action |
|---|---|---|
| Entry & Editing | ||
1-7 |
1-7 |
Set duration (64th to whole) |
. |
. |
Toggle dotted |
R |
R |
Toggle note/rest mode |
T |
T |
Toggle tie |
Enter |
Enter |
Insert note/rest at cursor |
↑ / ↓ |
↑ / ↓ |
Transpose selection |
| Navigation & Selection | ||
← / → |
← / → |
Previous / Next event |
Shift+←/→ |
Shift+←/→ |
Extend selection horizontally |
Cmd+↑/↓ |
Ctrl+↑/↓ |
Navigate within chord |
Cmd+Shift+↑/↓ |
Ctrl+Shift+↑/↓ |
Extend selection vertically |
Cmd+A |
Ctrl+A |
Select all (progressive) |
Esc |
Esc |
Clear selection / Cancel |
| Playback | ||
Space |
Space |
Play / Pause |
| History | ||
Cmd+Z |
Ctrl+Z |
Undo |
Cmd+Shift+Z |
Ctrl+Y |
Redo |
See the Interaction Guide for the complete keyboard reference.
| Guide | Description |
|---|---|
| 📖 Configuration | All config options for <RiffScore /> |
| 🎹 API Reference | Imperative API for script control |
| 📗 Cookbook | Task-oriented recipes and examples |
| Guide | Description |
|---|---|
| 🎨 Interaction Design | UX philosophy and editor states |
| ⌨️ Keyboard Navigation | Navigation state machine details |
| 🎯 Selection Model | Multi-selection and vertical extension |
| Guide | Description |
|---|---|
| 📘 Architecture | Technical overview and design principles |
| 🧱 Data Model | Score schema and quant system |
| 🔧 Commands | Command pattern reference |
| 🎼 Layout Engine | Engraving and positioning |
| 📜 ADRs | Architecture Decision Records |
| Guide | Description |
|---|---|
| 🤝 Contributing | Dev setup and guidelines |
| 🧪 Testing | Test patterns and fixtures |
| 📋 Changelog | Release history |
Control the editor programmatically from external scripts:
const api = window.riffScore.get('my-editor');
// Build a chord
api.select(1) // Measure 1
.addNote('C4', 'quarter')
.addNote('E4')
.addNote('G4')
.addTone('C5'); // Stack into chord
// Batch operations (single undo step)
api.beginTransaction();
for (let i = 0; i < 16; i++) {
api.addNote(`C${(i % 3) + 4}`, 'sixteenth');
}
api.commitTransaction('Scale run');
// Subscribe to changes
api.on('batch', (e) => console.log(`Committed: ${e.label}`));See the API Reference and Cookbook for all available methods.
riffscore/
├── src/ ← Library source
├── demo/ ← Next.js demo app
├── docs/ ← Documentation
├── dist/ ← Built library (ESM/CJS/DTS)
└── tsup.config.ts
# Install dependencies
npm install
cd demo && npm install
# Build library
npm run build
# Run demo
npm run demo:dev- Chord Symbols: Input and playback for lead sheets
- Import: ABC and MusicXML import
- Clipboard API: Copy, cut, and paste operations
- Move Operations: Drag-and-drop and keyboard-based event moving
