Skip to content

A self-hostable, embeddable sheet music editor for React. Interactive, configurable, and SMuFL compliant with no platform lock-in.

License

Notifications You must be signed in to change notification settings

joekotvas/RiffScore

Repository files navigation

RiffScore

npm version license

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.

RiffScore Editor

Installation

npm install riffscore

Quick Start

import { RiffScore } from 'riffscore';

function App() {
  return <RiffScore id="my-editor" />;
}

That's it! RiffScore renders a fully interactive grand staff editor with sensible defaults.

With Configuration

<RiffScore id="my-editor" config={{
  score: { 
    staff: 'treble',      // 'grand' | 'treble' | 'bass' | 'alto' | 'tenor'
    measureCount: 4,
    keySignature: 'G'
  }
}} />

See Configuration for all options.

Read-Only Mode

<RiffScore config={{
  ui: { showToolbar: false },
  interaction: { isEnabled: false }
}} />

See Interaction Configuration for more display modes.

Programmatic Control

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 selection

See the Cookbook for more recipes.


Features

Core Editing

  • 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.

Machine-Addressable API

  • 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) and api.on('batch', callback).
  • Transaction Batching: Atomic operations with beginTransaction/commitTransaction for single undo steps.
  • Playback API: play(), pause(), stop(), rewind(), setInstrument() for programmatic audio control.

Engines

  • 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).

Keyboard Shortcuts

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.


Documentation

Getting Started

Guide Description
📖 Configuration All config options for <RiffScore />
🎹 API Reference Imperative API for script control
📗 Cookbook Task-oriented recipes and examples

Deep Dives

Guide Description
🎨 Interaction Design UX philosophy and editor states
⌨️ Keyboard Navigation Navigation state machine details
🎯 Selection Model Multi-selection and vertical extension

Architecture

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

Contributing

Guide Description
🤝 Contributing Dev setup and guidelines
🧪 Testing Test patterns and fixtures
📋 Changelog Release history

Imperative API

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.


Repository Structure

riffscore/
├── src/        ← Library source
├── demo/       ← Next.js demo app
├── docs/       ← Documentation
├── dist/       ← Built library (ESM/CJS/DTS)
└── tsup.config.ts

Development

# Install dependencies
npm install
cd demo && npm install

# Build library
npm run build

# Run demo
npm run demo:dev

Coming Soon

  • 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