Notes falling onto a keyboard — canvas blocks, CSS keys, no framework in the frame loop. Drop any NSF below and watch it play.
0 framework renders a frame · ~6 KB gzipped · 0 ms when paused or off screen · 88 keys
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} />