- Denominate the canvas in bars (lengthBars, default 256) instead of a raw beat
count; canvasBeats(sig) = lengthBars * beatsPerBar, so it spans exactly 256
bars in any signature. Backing arrays sized for the widest case (5/4 -> 1280
beats). Playback still stops at lastFilledBeat, so the wider empty canvas adds
no trailing silence.
- Roll: draw with viewport culling (iterate only the beats scrolled into view)
so the ~16x-wider canvas stays cheap to redraw and scrolls smoothly.
- Persistence: store bars= (was len= in beats) and write cells only up to the
last filled beat; old files without bars= load the default 256-bar canvas with
their cells intact. .sng import grows the canvas in bars as needed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>