Piano roll
@xromdev/pianoroll v0.2.0 · MITNotes falling onto a keyboard: a block's bottom edge touches its key at the instant the note sounds, its length is the duration, its colour the voice. The blocks are canvas, the keys are DOM and CSS, and no frame goes through a framework — the view follows your clock itself and writes to a key only when that key changes. Below, any NSF is decoded into notes from what the sound chip does, and played.
- framework renders per frame
- 0
- framework renders per frame
- gzipped, React optional
- ~6 KB
- gzipped, React optional
- when paused or scrolled away
- 0 ms
- when paused or scrolled away
- keys, in a real piano’s proportions
- 88
- keys, in a real piano’s proportions
or drop one here — it stays in your browser
Demo tune
four bars from the APU playground, looped
pulse 1pulse 2trianglenoise
Use it — any page
import { PianoRollView } from '@xromdev/pianoroll';
import '@xromdev/pianoroll/pianoroll.css';
const roll = new PianoRollView(document.querySelector('#roll'), { lookAhead: 2.5 });
roll.setNotes([
// midi, start and duration in seconds; the track picks the colour
{ midi: 60, start: 0, duration: 0.5, track: 'pulse1' },
{ midi: 64, start: 0.5, duration: 0.5, track: 'pulse2', velocity: 0.6 },
{ midi: 43, start: 0, duration: 1, track: 'triangle' },
]);
roll.play(() => audioContext.currentTime - startedAt); // follows your clockUse it — React
import { PianoRoll } from '@xromdev/pianoroll/react';
import '@xromdev/pianoroll/pianoroll.css';
// With clock, the roll animates on its own frames — React never re-renders for it.
<PianoRoll notes={notes} clock={() => audio.currentTime} height={420} />
// Or drive it yourself — a scrubber, a paused picture:
<PianoRoll notes={notes} time={position} />