- Pad row now shows beatsPerBar × subdivision pads, each individually toggleable (the subdivision control sets pad resolution). Subdivision pads render smaller; downbeats labeled; group/beat gaps preserved. - Mask (beatsOn) is now per-step; playhead tracks the current step. recomputeLane remaps on grouping/subdivision change and migrates legacy per-beat masks (saved data, short share patterns) by expanding across subs. - Share language: =pattern is now per-step (len = beats × sub); short per-beat patterns still accepted and expanded. README updated. - Removed the Sig time-signature preset dropdown (confusing vs subdivision). - Help dialog: link to git.varasys.io/VARASYS/metronome + note that it's a single-page app you can save & run offline, but file:// won't auto-save the set list (export a backup). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5.4 KiB
Stackable Metronome
A browser polymetric groove trainer / metronome — and the design mockup for a Raspberry Pi Pico hardware build. Stack as many "meter lanes" as you like; each is its own little metronome with a grouping, subdivision, drum voice and per-beat pattern. Layering lanes produces polymeter and true ratio polyrhythm.
Live: https://metronome.varasys.io
It's a single page (index.html) plus a vendored QR library — no build step,
no framework. State (presets, set lists, practice log, theme) lives in
localStorage.
Features
- Meter lanes — grouping (odd meters), subdivision, GM drum voice, per‑beat on/off pattern (rests), mute, live measure counter.
- Polyrhythm — a per‑lane poly toggle fits a lane's beats evenly into lane 1's bar (e.g. 5‑over‑4, 3‑over‑2).
- Practice — gap/mute trainer (play N / mute M bars) and a tempo ramp with a start BPM and signed step.
- Set lists — named, ordered lists of saved setups; ▶ loads + starts an item, N advances; each play is logged for cross‑day comparison.
- Sharing — copy a link (with QR) to your current settings or a whole set list.
- Theming — System / Light / Dark.
The share language
A compact, human‑readable text encodes a full configuration (a patch). It's what goes in a share link, and you can hand‑write or edit it.
Patch grammar
v1 ; t<bpm> [; vol<pct>] ; <lane> ; <lane> … [; tr<play>/<mute>] [; rmp<start>/<step>/<every>]
| Token | Meaning | Example |
|---|---|---|
v1 |
format version (always first) | v1 |
t<bpm> |
tempo | t120 |
vol<pct> |
master volume 0–100 | vol70 |
tr<play>/<mute> |
gap trainer: play N bars, mute M | tr2/2 |
rmp<start>/<step>/<every> |
tempo ramp: start BPM, ±step, every N bars | rmp80/5/4 |
<lane> |
a meter lane (see below) | kick:4 |
Tokens are joined with ;. tr and rmp are omitted when off.
Lane grammar
<sound> : <grouping> [ / <sub> ] [ = <pattern> ] [ ~ ] [ ! ]
- sound — one of:
beep,kick,snare,rim,clap,hatClosed,hatOpen,ride,crash,tomLow,tomMid,tomHigh,tambourine,cowbell,woodblock,claves,jamblock(unknown →beep). - grouping — beats per bar, optionally grouped for odd meters:
4,3,2+2+3. The first beat of each group is accented. /sub— subdivision:1quarter (default),2eighth,3triplet,4sixteenth,6sextuplet. This also sets how many pads each beat splits into (a beat becomessubindividually‑toggleable steps). Omit for quarter.=pattern— per‑step on/off asx/., length = beats per bar ×sub(one char per pad). Omit = all on. e.g.4=.x.xis a backbeat on 2 & 4;4/4=x..x..x.x...x...is a sixteenth‑grid pattern. A short pattern whose length equals just the beat count is still accepted and expanded across each beat's subdivisions (back‑compat).~— polyrhythm: fit this lane's beats evenly into lane 1's bar.!— mute the lane.
Examples
| Patch / lane | What it is |
|---|---|
kick:4 |
kick on 4 quarter beats |
snare:4=.x.x |
snare backbeat (2 & 4) |
hatClosed:4/2 |
eighth‑note hi‑hats |
claves:5~ |
5 evenly across lane 1's bar (5‑over‑4 if lane 1 is 4) |
kick:2+2+3=x..x..x |
7/8, kick on each group start |
cowbell:3+2/2 |
5/4 grouped 3+2, eighth subdivision |
Full: v1;t120;kick:4;snare:4=.x.x;hatClosed:4/2;tr2/2 |
backbeat groove with gap trainer |
In URLs
- Settings:
…/#p=<patch>— readable, e.g.…/#p=v1;t120;kick:4;claves:5~ - Set list:
…/#sl=<base64url>— a JSON{title, description, items[]}where each item's config is a patch string. Used because titles/notes are free text.
Opening such a link applies the settings (or imports the set list) on load, then clears the hash so a refresh won't re‑import.
Sharing
In the set‑list panel's ⋯ menu:
- Share settings link / Share set‑list link open a dialog with the link to Copy or Open.
- QR ↗ opens a third‑party QR service (api.qrserver.com) with the link in its URL so you can scan it on a phone. A banner warns you it's external — confirm the QR decodes to the shown link before trusting it. (No QR is generated locally.)
- Export all / Import file back up presets + set lists + logs as a JSON file.
Keyboard shortcuts
| Key | Action |
|---|---|
P |
play / stop |
T |
tap tempo |
↑ / ↓ |
tempo ±1 (Shift = ±10) |
A |
add meter lane |
1–9 |
mute lane N |
R |
toggle the set‑list panel |
N |
next set‑list item |
? |
shortcuts help |
Esc |
close dialog / panel |
Versioning
VERSION holds the formal version. deploy.sh stamps the served page:
- Formal — a clean commit tagged
v<VERSION>→X.Y.Z. - Dev — anything else →
X.Y.Z-dev.<utc-timestamp>.<short-sha>[.dirty].
Cut a release with ./release.sh [X.Y.Z] (bumps VERSION + tags v<VERSION>),
then push the tag and deploy.
Deploy
./deploy.sh copies index.html (version‑stamped) into the Caddy
web root and smoke‑tests the live URL. No restart needed (file_server picks up
changes immediately).
Files
| File | Purpose |
|---|---|
index.html |
the whole app |
deploy.sh |
publish to the Caddy web root |
release.sh |
tag a formal version |
VERSION |
formal version string |