metronome/README.md
Me Here 5320da4325 Add QR share dialog (vendored qrcode.js) + README documenting the language
- Share menu now opens a dialog with a copyable link AND a QR code (scan to open
  on a phone); generated locally by vendored qrcode-generator (MIT). deploy.sh
  publishes qrcode.js alongside index.html.
- README documents the share language grammar, sounds, URL forms, shortcuts,
  versioning and deploy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 17:34:26 -05:00

143 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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, perbeat
on/off pattern (rests), mute, live measure counter.
- **Polyrhythm** — a perlane *poly* toggle fits a lane's beats evenly into lane 1's
bar (e.g. 5over4, 3over2).
- **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 crossday 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, humanreadable text encodes a full configuration (a *patch*). It's what
goes in a share link, and you can handwrite 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 0100 | `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 (clicks per beat): `1` quarter (default), `2` eighth,
`3` triplet, `4` sixteenth, `6` sextuplet. Omit for quarter.
- **`=pattern`** — perbeat on/off as `x`/`.`, length = beats per bar. Omit = all on.
e.g. `=.x.x` puts a backbeat on 2 & 4.
- **`~`** — 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` | eighthnote hihats |
| `claves:5~` | 5 evenly across lane 1's bar (5over4 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 reimport.
## Sharing & QR
In the setlist panel's **⋯** menu:
- **Share settings link** / **Share setlist link** open a dialog with the link and
a **QR code** (scan to open on a phone). Copy or Open from there.
- **Export all / Import file** back up presets + set lists + logs as a JSON file.
QR codes are generated locally by the vendored `qrcode.js`; the link never leaves
your browser. Very long setlist links may exceed QR capacity — copy those instead.
## Keyboard shortcuts
| Key | Action |
|-----|--------|
| `Space` | start / stop |
| `T` | tap tempo |
| `↑` / `↓` | tempo ±1 (`Shift` = ±10) |
| `A` | add meter lane |
| `1``9` | mute lane N |
| `R` | toggle the setlist panel |
| `N` | next setlist 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` (versionstamped) and `qrcode.js` into the Caddy
web root and smoketests the live URL. No restart needed (`file_server` picks up
changes immediately).
## Files
| File | Purpose |
|------|---------|
| `index.html` | the whole app |
| `qrcode.js` | vendored QR generator (Kazuhiko Arase, MIT) |
| `deploy.sh` | publish to the Caddy web root |
| `release.sh` | tag a formal version |
| `VERSION` | formal version string |
## Credits
QR generation by [qrcode-generator](https://github.com/kazuhikoarase/qrcode-generator)
(© Kazuhiko Arase, MIT).