Phase 0: refresh README to current state; add 'kit' embed variant
README was stale (pre-dating several shipped changes). Rewrite it to match reality:
- voices are all synthesized now (KIT_ALIAS -> 808/909); drop the VCSL samples
narrative, the @BUILD:samples wording, and the sample credits.
- document the lean-widget + separate info-<device>.html page model (was 'Open=Info').
- add kit.html + all info-*.html to the Pages table; add the new src/ partials
(header/footer/chrome/progbox/infoembed), pico/ firmware, and pico-main.py to Files/Build.
- document the share-grammar additions: GM note numbers, Euclidean (k,n[,rot]), per-lane @<db> gain.
- add a 'Build it (hardware)' section for the PM_K-1 Kit + MicroPython firmware.
embed.js: add the 'kit' form factor to the variant map (it previously fell back to micro),
so data-varasys-metronome="kit" embeds kit.html as the README now documents.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1afa56b078
commit
5fc962f0c4
2 changed files with 124 additions and 108 deletions
228
README.md
228
README.md
|
|
@ -5,64 +5,76 @@ A landing page is the front door; the main app is the **PM_E‑1 PolyMeter Edito
|
||||||
web app where you stack as many "meter lanes" as you like, each its own little metronome
|
web app where you stack as many "meter lanes" as you like, each its own little metronome
|
||||||
with a grouping, subdivision, drum voice and a per‑step pattern with accents. Layering lanes
|
with a grouping, subdivision, drum voice and a per‑step pattern with accents. Layering lanes
|
||||||
produces polymeter and true ratio polyrhythm. The same engine drives an ever‑expanding library
|
produces polymeter and true ratio polyrhythm. The same engine drives an ever‑expanding library
|
||||||
of **form‑factor concepts** (idealized and buildable hardware mockups) and ships as an
|
of **form‑factor concepts** (idealized and buildable hardware mockups), ships as an
|
||||||
**embeddable widget** anyone can drop into their own page.
|
**embeddable widget** anyone can drop into their own page, and even runs as **firmware** on a
|
||||||
|
real Raspberry Pi Pico build (the **PM_K‑1 Kit**).
|
||||||
|
|
||||||
**Live:** https://metronome.varasys.io · **Source:** https://codeberg.org/VARASYS/metronome
|
**Live:** https://metronome.varasys.io · **Source:** https://codeberg.org/VARASYS/metronome
|
||||||
|
|
||||||
Every **deployed page is a single, self‑contained `.html` file** — **zero dependencies**:
|
Every **deployed page is a single, self‑contained `.html` file** — **zero dependencies**:
|
||||||
no framework, no CDN libraries, nothing fetched at runtime. They're assembled by a small
|
no framework, no CDN libraries, nothing fetched at runtime. They're assembled by a small
|
||||||
build step (`build.sh`) that inlines a shared engine, the seed set lists, base styling and
|
build step (`build.sh`) that inlines a shared engine, the seed set lists, base styling and
|
||||||
the audio samples + brand assets (kept in `assets/`) into each page, so the sources stay lean.
|
the brand assets (kept in `assets/`) into each page, so the sources stay lean. Every voice is
|
||||||
State (set lists, the practice log, theme and UI preferences) lives in `localStorage`.
|
**synthesized** in Web Audio — there are no audio samples to load. State (set lists, the
|
||||||
|
practice log, theme and UI preferences) lives in `localStorage`.
|
||||||
|
|
||||||
## Pages
|
## Pages
|
||||||
|
|
||||||
|
The site is **one editor + a gallery of form factors**, and each form factor is split into a
|
||||||
|
**lean widget page** and a **separate info page**:
|
||||||
|
|
||||||
|
- **`<device>.html`** — just the live widget (front view, controls, program box). This is what
|
||||||
|
`?embed=1` serves and what the landing embeds; it never ships the BOM/narrative.
|
||||||
|
- **`info-<device>.html`** — the spec page: it embeds the live widget at the top, then the
|
||||||
|
description, dimensioned drawings and a priced **Bill of Materials** (for the buildable hardware).
|
||||||
|
|
||||||
| URL | What |
|
| URL | What |
|
||||||
|-----|------|
|
|-----|------|
|
||||||
| [`/`](https://metronome.varasys.io/) `index.html` | **Concepts** — the landing / form‑factor gallery; each box embeds the live widget |
|
| [`/`](https://metronome.varasys.io/) `index.html` | **Concepts** — the landing / form‑factor gallery; each box embeds the live widget (Open ↗ / Specs & info ⓘ) |
|
||||||
| `/editor.html` | **PM_E‑1 — PolyMeter Editor** (the main app) |
|
| `/editor.html` · `/info-editor.html` | **PM_E‑1 — PolyMeter Editor** (the main app) + its overview |
|
||||||
| `/player.html` | **PM_C‑1 Concept** — idealized concept device (full display + set‑list nav, theme, fullscreen "stage" view) |
|
| `/kit.html` · `/info-kit.html` | **PM_K‑1 Kit** — buildable Raspberry Pi Pico touchscreen unit (52Pi EP‑0172); info page has the wiring, parts and firmware |
|
||||||
| `/teacher.html` | **PM_T‑1 Teacher** — studio / lesson console (colour TFT, arcade buttons, 1/4″ instrument pass‑through with analog click injection) |
|
| `/player.html` · `/info-player.html` | **PM_C‑1 Concept** — idealized concept device (full display + set‑list nav, theme, fullscreen "stage" view) |
|
||||||
| `/stage.html` | **PM_S‑1 Stage** — foot‑pedal stompbox (two footswitches, expression‑pedal in, RGB beat light, instrument pass‑through) |
|
| `/teacher.html` · `/info-teacher.html` | **PM_T‑1 Teacher** — studio / lesson console (colour TFT, arcade buttons, 1/4″ instrument pass‑through with analog click injection) |
|
||||||
| `/micro.html` | **PM_P‑1 Practice** — inline practice bar (instrument in / out pass‑through, clickable thumb‑roller, 14‑segment display) |
|
| `/stage.html` · `/info-stage.html` | **PM_S‑1 Stage** — foot‑pedal stompbox (two footswitches, expression‑pedal in, RGB beat light, instrument pass‑through) |
|
||||||
| `/showcase.html` | **PM_D‑1 Display** — pyramid display piece; the pendulum is an RGB light bar combining every lane's subdivisions/accents |
|
| `/micro.html` · `/info-micro.html` | **PM_P‑1 Practice** — inline practice bar (instrument in / out pass‑through, clickable thumb‑roller, 14‑segment display) |
|
||||||
|
| `/showcase.html` · `/info-showcase.html` | **PM_D‑1 Display** — pyramid display piece; the pendulum is an RGB light bar combining every lane's subdivisions/accents |
|
||||||
| `/embed.html` · `/embed.js` | embed docs and the drop‑in loader |
|
| `/embed.html` · `/embed.js` | embed docs and the drop‑in loader |
|
||||||
|
| `/pico-main.py` | the PM_K‑1 MicroPython firmware (download) |
|
||||||
|
|
||||||
Each form‑factor page is self‑contained ("Open" = "Info"): a more‑detailed description,
|
The buildable units (Teacher, Stage, Practice, Display, Kit) carry a priced BOM on their info
|
||||||
the live device with front + top/side dimensioned views and loading instructions, and an
|
page; the Editor (web app) and Concept have none. Every page shares the same VARASYS header
|
||||||
expandable **Spec & BOM** (priced, for the buildable hardware). The buildable units are the
|
(official logo with baked‑in tagline, nav, theme toggle). The editor also shows a subtle live
|
||||||
Teacher, Stage, Micro and Showcase; the Editor (web app) and Initial (concept) have no BOM.
|
**program string** of what's loaded — editable, with copy/paste — under the app (press `Enter`
|
||||||
|
or paste to apply; see [the share language](#the-share-language)).
|
||||||
|
|
||||||
Each page carries the same VARASYS header (logo + tagline, nav, theme toggle). The editor
|
Because nothing loads from the network, you can save a page (`Ctrl`/`⌘`+`S`) and open it
|
||||||
also shows a subtle live **program string** of what's loaded — editable, with copy/paste —
|
straight from disk to run fully offline. One catch from a local `file://`: the browser may not
|
||||||
under the app (press `Enter` or paste to apply; see [the share language](#the-share-language)).
|
persist `localStorage` between sessions, so use **Export all** (set‑list **⋯** menu) to back up.
|
||||||
|
|
||||||
Because nothing loads from the network, you can save the page (`Ctrl`/`⌘`+`S`) and
|
|
||||||
open it straight from disk to run fully offline. One catch from a local `file://`:
|
|
||||||
the browser may not persist `localStorage` between sessions, so use **Export all**
|
|
||||||
(set‑list **⋯** menu) to back up your work.
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **Meter lanes** — grouping (odd meters), subdivision (incl. swing), a drum/percussion
|
- **Meter lanes** — grouping (odd meters), subdivision (incl. swing), a drum/percussion
|
||||||
voice, per‑**step dynamics** (accent / normal / ghost / mute), mute, live measure counter.
|
voice, per‑**step dynamics** (accent / normal / ghost / mute), mute, live measure counter.
|
||||||
- **Sounds** — a sampled acoustic kit plus synthesized **808 / 909** and electronic voices;
|
- **Sounds** — every voice is **synthesized** in Web Audio: a friendly drum kit
|
||||||
click each pad to set its dynamics; pick a *swing* subdivision for a triplet feel.
|
(`kick`, `snare`, `hatClosed`, …) rendered with the **808 / 909** voices, the 808/909 voices
|
||||||
|
by name, and electronic/percussion tones. No samples are loaded.
|
||||||
|
- **Per‑lane gain** — a dB trim knob per lane (`@<db>` in the share language), applied at
|
||||||
|
schedule time so changing it never stutters playback.
|
||||||
- **Polyrhythm** — a per‑lane *poly* toggle fits a lane's beats evenly into lane 1's
|
- **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).
|
bar (e.g. 5‑over‑4, 3‑over‑2).
|
||||||
|
- **Euclidean rhythms** — spread *k* hits evenly across *n* steps with `(k,n[,rot])`.
|
||||||
- **Practice** — gap/mute trainer (play N / mute M bars) and a tempo ramp with a
|
- **Practice** — gap/mute trainer (play N / mute M bars) and a tempo ramp with a
|
||||||
start BPM and signed step.
|
start BPM and signed step.
|
||||||
- **Set lists** — named, ordered lists of saved setups; **cue** across lists and commit
|
- **Set lists** — named, ordered lists of saved setups; **cue** across lists and commit
|
||||||
on a bar/beat boundary with no audible gap (see **Live performance**); each play is
|
on a bar/beat boundary with no audible gap (see **Live performance**); each play is logged.
|
||||||
logged for cross‑day comparison.
|
|
||||||
- **Sharing** — copy a link to your current settings or a whole set list.
|
- **Sharing** — copy a link to your current settings or a whole set list.
|
||||||
- **Theming** — System / Light / Dark.
|
- **Theming** — System / Light / Dark.
|
||||||
|
|
||||||
## The share language
|
## The share language
|
||||||
|
|
||||||
A compact, human‑readable text encodes a full configuration (a *patch*). It's what
|
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.
|
goes in a share link, the editor's program box, and a device's program list. You can
|
||||||
|
hand‑write or edit it.
|
||||||
|
|
||||||
### Patch grammar
|
### Patch grammar
|
||||||
|
|
||||||
|
|
@ -86,29 +98,26 @@ Tokens are joined with `;`. `tr` and `rmp` are omitted when off.
|
||||||
### Lane grammar
|
### Lane grammar
|
||||||
|
|
||||||
```
|
```
|
||||||
<sound> : <grouping> [ / <sub> ] [ = <pattern> ] [ ~ ] [ ! ]
|
<sound> : <grouping> [ / <sub> ] [ (<k>,<n>[,<rot>]) ] [ = <pattern> ] [ @ <db> ] [ ~ ] [ ! ]
|
||||||
```
|
```
|
||||||
|
|
||||||
- **sound** — the acoustic kit: `beep`, `kick`, `snare`, `rim`, `clap`, `hatClosed`,
|
- **sound** — a synthesized voice. Friendly kit names (rendered with 808/909):
|
||||||
`hatOpen`, `ride`, `crash`, `tomLow`, `tomMid`, `tomHigh`, `tambourine`, `cowbell`,
|
`beep`, `kick`, `snare`, `rim`, `clap`, `hatClosed`, `hatOpen`, `ride`, `crash`, `tomLow`,
|
||||||
`woodblock`, `claves`, `jamblock` (kick, snare, closed‑hat, crash, toms, tambourine,
|
`tomMid`, `tomHigh`, `tambourine`, `cowbell`, `woodblock`, `claves`; the drum‑machine voices
|
||||||
cowbell, woodblock and claves play embedded CC0 samples; `beep`, `clap`, `rim`,
|
by name — `kick808 snare808 clap808 hat808 openHat808 cowbell808 tom808` and
|
||||||
`hatOpen` and `ride` stay synthesized — VCSL has no clean source for those); plus
|
`kick909 snare909 clap909 hat909 ride909 crash909`; or a **General‑MIDI note number**
|
||||||
synthesized drum machines —
|
(`36`→kick, `38`→snare, `42`→closed hat, …). Unknown → `beep`.
|
||||||
`kick808 snare808 clap808 hat808 openHat808 cowbell808 tom808` and
|
- **grouping** — beats per bar, optionally grouped for odd meters: `4`, `3`, `2+2+3`.
|
||||||
`kick909 snare909 clap909 hat909 ride909 crash909`. Unknown → `beep`.
|
Groups get a visual divider; accents are per‑step (see `=pattern`).
|
||||||
- **grouping** — beats per bar, optionally grouped for odd meters: `4`, `3`,
|
- **`/sub`** — subdivision: `1` quarter (default), `2` eighth, `3` triplet, `4` sixteenth,
|
||||||
`2+2+3`. Groups get a visual divider; accents are per‑step (see `=pattern`).
|
`6` sextuplet — also sets how many **pads** each beat splits into. Append **`s`** for **swing**
|
||||||
- **`/sub`** — subdivision: `1` quarter (default), `2` eighth, `3` triplet,
|
on even subdivisions (`2s`, `4s`) to delay the off‑beats to a 2:1 triplet feel.
|
||||||
`4` sixteenth, `6` sextuplet. This also sets how many **pads** each beat splits
|
- **`(k,n[,rot])`** — **Euclidean** fill: place `k` hits as evenly as possible across `n`
|
||||||
into. Append **`s`** for **swing** on even subdivisions — `2s` (swung eighths) or
|
steps, optionally rotated by `rot`. e.g. `kick:4(3,8)`.
|
||||||
`4s` (swung sixteenths) delay the off‑beats to a triplet (2:1) feel. Omit for quarter.
|
- **`=pattern`** — per‑**step dynamics**, one char per pad: **`X`** accent, **`x`** normal,
|
||||||
- **`=pattern`** — per‑**step dynamics**, one char per pad: **`X`** accent, **`x`**
|
**`g`** ghost (soft), **`.`** `-` `_` mute (rest). Length = beats × `sub`. Omit to get the
|
||||||
normal, **`g`** ghost (soft), **`.`** mute (rest). Length = beats per bar × `sub`. Omit to get the
|
default — first step of each beat accented, the rest normal. e.g. `4=.X.X` accents 2 & 4.
|
||||||
default — the first step of **each beat** accented, the rest normal (click a pad in
|
- **`@<db>`** — per‑lane gain trim in decibels, e.g. `@-3` or `@+2`.
|
||||||
the UI to cycle accent → normal → ghost → mute). e.g. `4=.X.X` accents the backbeat (2 & 4);
|
|
||||||
`4/2s` is swung eighths with the default accents. (Legacy `x`/`.` on/off patterns and
|
|
||||||
short beat‑count patterns still parse.)
|
|
||||||
- **`~`** — polyrhythm: fit this lane's beats evenly into **lane 1's** bar.
|
- **`~`** — polyrhythm: fit this lane's beats evenly into **lane 1's** bar.
|
||||||
- **`!`** — mute the lane.
|
- **`!`** — mute the lane.
|
||||||
|
|
||||||
|
|
@ -120,28 +129,27 @@ Tokens are joined with `;`. `tr` and `rmp` are omitted when off.
|
||||||
| `snare:4=.X.X` | accented snare backbeat (2 & 4) |
|
| `snare:4=.X.X` | accented snare backbeat (2 & 4) |
|
||||||
| `hatClosed:4/2` | eighth‑note hi‑hats (downbeat of each beat accented) |
|
| `hatClosed:4/2` | eighth‑note hi‑hats (downbeat of each beat accented) |
|
||||||
| `ride:4/2s` | **swung** eighth‑note ride |
|
| `ride:4/2s` | **swung** eighth‑note ride |
|
||||||
|
| `kick:4(3,8)` | a 3‑over‑8 Euclidean kick |
|
||||||
| `claves:5~` | 5 evenly across lane 1's bar (5‑over‑4 if lane 1 is `4`) |
|
| `claves:5~` | 5 evenly across lane 1's bar (5‑over‑4 if lane 1 is `4`) |
|
||||||
|
| `hat909:4/2@-4` | eighth 909 hats, trimmed −4 dB |
|
||||||
| `kick:2+2+3=x..x..x` | 7/8, kick on each group start |
|
| `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 |
|
| **Full:** `v1;t120;kick:4;snare:4=.x.x;hatClosed:4/2;tr2/2` | backbeat groove with gap trainer |
|
||||||
|
|
||||||
### In URLs
|
### In URLs
|
||||||
|
|
||||||
- **Settings:** `…/#p=<patch>` — readable, e.g.
|
- **Settings:** `…/#p=<patch>` — readable, e.g. `…/#p=v1;t120;kick:4;claves:5~`
|
||||||
`…/#p=v1;t120;kick:4;claves:5~`
|
- **Set list:** `…/#sl=<base64url>` — a JSON `{title, description, items[]}` where each
|
||||||
- **Set list:** `…/#sl=<base64url>` — a JSON `{title, description, items[]}` where
|
item's config is a patch string.
|
||||||
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
|
Opening such a link applies the settings (or imports the set list) on load, then clears
|
||||||
clears the hash so a refresh won't re‑import.
|
the hash so a refresh won't re‑import.
|
||||||
|
|
||||||
## Sharing
|
## Sharing
|
||||||
|
|
||||||
In the set‑list panel's **⋯** menu:
|
In the set‑list panel's **⋯** menu:
|
||||||
- **Share settings link** / **Share set‑list link** open a dialog with the link to
|
- **Share settings link** / **Share set‑list link** open a dialog with the link to **Copy**
|
||||||
**Copy** or **Open**. The link encodes everything in the URL — nothing is uploaded.
|
or **Open**. The link encodes everything in the URL — nothing is uploaded.
|
||||||
- **Export all / Import file** back up your set lists and practice log as a JSON
|
- **Export all / Import file** back up your set lists and practice log as a JSON file.
|
||||||
file (a legacy `presets` field is included for backward compatibility).
|
|
||||||
|
|
||||||
## Embedding
|
## Embedding
|
||||||
|
|
||||||
|
|
@ -155,16 +163,30 @@ container and the loader script — it builds an `<iframe>` to the chrome‑stri
|
||||||
<script src="https://metronome.varasys.io/embed.js"></script>
|
<script src="https://metronome.varasys.io/embed.js"></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
- `data-varasys-metronome` — variant: `editor` · `initial` · `teacher` · `stage` · `micro` · `showcase`.
|
- `data-varasys-metronome` — variant: `editor` · `kit` · `initial` · `teacher` · `stage` · `micro` · `showcase`.
|
||||||
- `data-patch` — a [patch string](#patch-grammar) (maps to `#p=`); or `data-setlist`
|
- `data-patch` — a [patch string](#patch-grammar) (maps to `#p=`); or `data-setlist`
|
||||||
for a set‑list code (maps to `#sl=`).
|
for a set‑list code (maps to `#sl=`).
|
||||||
- `data-width` / `data-height` — optional initial size (default `100%` × `300px`;
|
- `data-width` / `data-height` — optional initial size (default `100%` × `300px`;
|
||||||
height then tracks the widget, which posts `{type:'varasys-h', h}` to the parent).
|
height then tracks the widget, which posts `{type:'varasys-h', h}` to the parent).
|
||||||
|
|
||||||
Prefer your own iframe? `…/<variant>.html?embed=1#p=<patch>` works directly. The
|
Prefer your own iframe? `…/<variant>.html?embed=1#p=<patch>` works directly. The
|
||||||
[Concepts landing](index.html) dogfoods this exact mechanism (every box is a live widget).
|
[Concepts landing](index.html) and every `info-*.html` page dogfood this exact mechanism.
|
||||||
See `/embed.html`.
|
See `/embed.html`.
|
||||||
|
|
||||||
|
## Build it (hardware) — PM_K‑1 "Kit"
|
||||||
|
|
||||||
|
The **PM_K‑1 Kit** runs the same engine and program strings on a real device you can build today:
|
||||||
|
a **Raspberry Pi Pico** on the **52Pi EP‑0172 "Pico Breadboard Kit Plus"** — a 3.5″ ST7796
|
||||||
|
320×480 capacitive‑touch screen (GT911), a PSP joystick, a WS2812 RGB LED, a buzzer and two
|
||||||
|
buttons, all pre‑wired. See **`/info-kit.html`** for the pinout, parts (~$45 incl. Pico) and
|
||||||
|
flashing steps. Firmware lives in **`pico/`**:
|
||||||
|
|
||||||
|
- **`pico/main.py`** — single‑file **MicroPython** firmware: an ST7796 driver, GT911 touch,
|
||||||
|
WS2812 RGB, PWM buzzer, ADC joystick, baked anti‑aliased fonts, and the polymeter engine.
|
||||||
|
It parses the same program strings as the web editor. Flash MicroPython, copy `main.py`,
|
||||||
|
edit the `PROGRAMS` list to change grooves. Download: `/pico-main.py`.
|
||||||
|
- **`pico/gen_font.py`** — generates the baked anti‑aliased fonts embedded in the firmware.
|
||||||
|
|
||||||
## Keyboard shortcuts
|
## Keyboard shortcuts
|
||||||
|
|
||||||
| Key | Action |
|
| Key | Action |
|
||||||
|
|
@ -190,35 +212,33 @@ See `/embed.html`.
|
||||||
The set list is performance-ready: you can line up where you're going next without
|
The set list is performance-ready: you can line up where you're going next without
|
||||||
disturbing what's playing, then commit on a musical boundary — no audible gap.
|
disturbing what's playing, then commit on a musical boundary — no audible gap.
|
||||||
|
|
||||||
- **Cue, then commit.** The arrows / `Home` / `End` / `PgUp` / `PgDn` move a *cue
|
- **Cue, then commit.** The arrows / `Home` / `End` / `PgUp` / `PgDn` move a *cue cursor*
|
||||||
cursor* (amber outline) through items — across set lists, without loading anything.
|
(amber outline) through items — across set lists, without loading anything. **`Enter`**
|
||||||
**`Enter`** commits the cued item with a **smooth** cutover at the next **bar**;
|
commits with a **smooth** cutover at the next **bar**; **`Shift`+`Enter`** is a **rude**
|
||||||
**`Shift`+`Enter`** is a **rude** cutover at the next **beat** ("wrong thing playing,
|
cutover at the next **beat**. `N` / `P` are immediate rude quick‑steps. `Esc` cancels.
|
||||||
fix it now"). `N` / `P` are immediate rude quick‑steps. `Esc` cancels an armed switch.
|
- **Bar‑length segments.** Give an item a **bar** count (Timers box, or `b<n>`) and a bar
|
||||||
- **Bar‑length segments.** Give an item a **bar** count (Timers box, or the `b<n>`
|
countdown (▦) shows bars remaining. With **Continue** on, it auto‑advances at the bar
|
||||||
patch token) and a bar countdown (▦) shows bars remaining. With **Continue** on, it
|
boundary — so a *song* is just a set list of segments that hand off seamlessly.
|
||||||
auto‑advances to the next item at the bar boundary — so a *song* is just a set list
|
- All transitions keep the clock continuous; the loaded item can live in a set list you're
|
||||||
of segments (each with its own tempo, ramp and bar length) that hand off seamlessly.
|
not currently viewing (the player names it).
|
||||||
- All transitions — manual or auto, beat or bar — keep the clock continuous; the loaded
|
|
||||||
item can even live in a set list you're not currently viewing (the player names it).
|
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
Every page is a source that shares code through `@BUILD:*` markers, so they all stay
|
Every page is a source that shares code through `@BUILD:*` markers, so they all stay in sync:
|
||||||
in sync:
|
|
||||||
|
|
||||||
- `/*@BUILD:include:src/…@*/` inlines a **shared partial** — the audio/scheduler
|
- `/*@BUILD:include:src/…@*/` inlines a **shared partial** — the audio/scheduler engine
|
||||||
engine (`src/engine.js`), the seed set lists (`src/setlists.js`, so every page ships
|
(`src/engine.js`), the seed set lists (`src/setlists.js`, so every page ships the **same
|
||||||
the **same default set lists** as the editor), and base styling (`src/base.css`:
|
default set lists**), base styling (`src/base.css`), the site **header/footer/chrome**
|
||||||
reset + brand palette + type + the shared site header / nav / BOM table styles).
|
(`src/header.html`, `src/footer.html`, `src/chrome.js`), the per‑device **program box**
|
||||||
- `@BUILD:favicon@`, `@BUILD:logo-*@`, `/*@BUILD:samples@*/{}` inline the base64
|
(`src/progbox.{html,js}`) and the info‑page **live‑widget embed** (`src/infoembed.{html,js}`).
|
||||||
assets from `assets/`.
|
- `@BUILD:favicon@`, `@BUILD:logo-dark@`, `@BUILD:logo-light@` inline the base64 assets from
|
||||||
|
`assets/` (the official logos already include the tagline).
|
||||||
|
|
||||||
`./build.sh` resolves every marker into a self‑contained page in `dist/` — the editor +
|
`./build.sh` resolves every marker into a self‑contained page in `dist/` (the Concepts landing,
|
||||||
the Concepts landing + editor + device/form-factor pages — and copies `embed.js` through as‑is
|
the editor, the device/form‑factor pages and their `info-*.html`), copies `embed.js` through
|
||||||
(the editor inlines the CC0 samples; the device pages pass an empty `SAMPLES` for pure synth).
|
as‑is, and copies the Pico firmware to `dist/pico-main.py`. `dist/` is generated, git‑ignored —
|
||||||
`dist/` is generated, git‑ignored — don't edit it by hand. `deploy.sh` runs the build first,
|
don't edit it by hand. `deploy.sh` runs the build first, so a deploy always serves freshly
|
||||||
so a deploy always serves freshly assembled pages.
|
assembled pages.
|
||||||
|
|
||||||
## Versioning
|
## Versioning
|
||||||
|
|
||||||
|
|
@ -227,9 +247,8 @@ so a deploy always serves freshly assembled pages.
|
||||||
- **Formal** — a clean commit tagged `v<VERSION>` → `X.Y.Z`.
|
- **Formal** — a clean commit tagged `v<VERSION>` → `X.Y.Z`.
|
||||||
- **Dev** — anything else → `X.Y.Z-dev.<utc-timestamp>.<short-sha>[.dirty]`.
|
- **Dev** — anything else → `X.Y.Z-dev.<utc-timestamp>.<short-sha>[.dirty]`.
|
||||||
|
|
||||||
Cut a release with `./release.sh [X.Y.Z]` — the optional arg bumps & commits
|
Cut a release with `./release.sh [X.Y.Z]` — the optional arg bumps & commits `VERSION`; it then
|
||||||
`VERSION`; it then tags the current commit `v<VERSION>` (requires a clean tree).
|
tags the current commit `v<VERSION>` (requires a clean tree). Push the tag, then deploy.
|
||||||
Push the tag, then deploy.
|
|
||||||
|
|
||||||
## Files
|
## Files
|
||||||
|
|
||||||
|
|
@ -237,12 +256,13 @@ Push the tag, then deploy.
|
||||||
|------|---------|
|
|------|---------|
|
||||||
| `index.html` | the **Concepts** landing / gallery (embeds each widget live) |
|
| `index.html` | the **Concepts** landing / gallery (embeds each widget live) |
|
||||||
| `editor.html` | the **PM_E‑1 editor** app (source, with `@BUILD:*` markers) |
|
| `editor.html` | the **PM_E‑1 editor** app (source, with `@BUILD:*` markers) |
|
||||||
| `src/header.html` · `src/footer.html` · `src/chrome.js` | shared header / footer / theme chrome, inlined into every page |
|
| `kit.html` · `player.html` · `teacher.html` · `stage.html` · `micro.html` · `showcase.html` | the device widget pages (PM_K‑1 Kit, PM_C‑1 Concept, Teacher, Stage, PM_P‑1 Practice, PM_D‑1 Display) |
|
||||||
| `player.html` · `teacher.html` · `stage.html` · `micro.html` · `showcase.html` | the device mockups (PM_C‑1 Concept / Teacher / Stage, PM_P‑1 Practice, PM_D‑1 Display) |
|
| `info-*.html` | per‑form‑factor spec pages (embed the live widget + description + dimensions + BOM) |
|
||||||
| `embed.html` · `embed.js` | embed docs and the drop‑in widget loader |
|
| `embed.html` · `embed.js` | embed docs and the drop‑in widget loader |
|
||||||
| `src/` | shared partials inlined into every page: `engine.js`, `setlists.js`, `base.css` |
|
| `src/` | shared partials inlined into every page: `engine.js`, `setlists.js`, `base.css`, `header.html`, `footer.html`, `chrome.js`, `progbox.{html,js}`, `infoembed.{html,js}` |
|
||||||
| `assets/` | base64 blobs inlined at build (samples, logos, favicon) |
|
| `assets/` | base64 blobs inlined at build (`favicon`, `logo-dark`, `logo-light`) |
|
||||||
| `build.sh` | resolve markers → self‑contained `dist/` pages |
|
| `pico/` | PM_K‑1 firmware: `main.py` (MicroPython), `gen_font.py` (font generator), `README.md` |
|
||||||
|
| `build.sh` | resolve markers → self‑contained `dist/` pages (+ `pico-main.py`) |
|
||||||
| `deploy.sh` | build, then publish to the Caddy web root |
|
| `deploy.sh` | build, then publish to the Caddy web root |
|
||||||
| `release.sh` | tag a formal version |
|
| `release.sh` | tag a formal version |
|
||||||
| `VERSION` | formal version string |
|
| `VERSION` | formal version string |
|
||||||
|
|
@ -252,19 +272,15 @@ Push the tag, then deploy.
|
||||||
|
|
||||||
Copyright (C) 2026 Varasys.
|
Copyright (C) 2026 Varasys.
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under
|
This program is free software: you can redistribute it and/or modify it under the terms of the
|
||||||
the terms of the **GNU Affero General Public License** as published by the Free
|
**GNU Affero General Public License** as published by the Free Software Foundation, either
|
||||||
Software Foundation, either version 3 of the License, or (at your option) any
|
version 3 of the License, or (at your option) any later version. See [`LICENSE`](LICENSE).
|
||||||
later version. See [`LICENSE`](LICENSE) for the full text.
|
|
||||||
|
|
||||||
Because the app is served over a network, the AGPL's §13 applies: anyone
|
Because the app is served over a network, the AGPL's §13 applies: anyone interacting with a
|
||||||
interacting with a hosted instance must be able to get its source — the public
|
hosted instance must be able to get its source — the public repository is
|
||||||
repository is **<https://codeberg.org/VARASYS/metronome>** (also linked from the
|
**<https://codeberg.org/VARASYS/metronome>** (also linked from the in‑app **?** help).
|
||||||
in‑app **?** help).
|
|
||||||
|
|
||||||
### Credits
|
### Credits
|
||||||
|
|
||||||
Acoustic drum one‑shots are from the **[Versilian Community Sample Library
|
All drum and percussion voices are **synthesized in Web Audio** (808/909‑style and electronic) —
|
||||||
(VCSL)](https://github.com/sgossner/VCSL)**, released under **CC0** (public
|
there are no audio samples. The on‑device fonts (PM_K‑1) are rendered from **DejaVu Sans**.
|
||||||
domain) — trimmed and downsampled, embedded inline. The 808/909 voices and the
|
|
||||||
electronic/percussion sounds are synthesized in Web Audio (no samples).
|
|
||||||
|
|
|
||||||
4
embed.js
4
embed.js
|
|
@ -5,7 +5,7 @@
|
||||||
* <script src="https://metronome.varasys.io/embed.js"></script>
|
* <script src="https://metronome.varasys.io/embed.js"></script>
|
||||||
*
|
*
|
||||||
* Attributes:
|
* Attributes:
|
||||||
* data-varasys-metronome editor | initial | teacher | stage | micro | showcase (which form factor)
|
* data-varasys-metronome editor | kit | initial | teacher | stage | micro | showcase (which form factor)
|
||||||
* data-patch a PolyMeter program/settings string (preloads it)
|
* data-patch a PolyMeter program/settings string (preloads it)
|
||||||
* data-setlist a base64url set-list code (alternative to data-patch)
|
* data-setlist a base64url set-list code (alternative to data-patch)
|
||||||
* data-width / data-height iframe size (default 100% × 300; height auto-grows)
|
* data-width / data-height iframe size (default 100% × 300; height auto-grows)
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* own ?embed=1 mode strips the site chrome) and auto-resizes to the widget's content.
|
* own ?embed=1 mode strips the site chrome) and auto-resizes to the widget's content.
|
||||||
*/
|
*/
|
||||||
(function () {
|
(function () {
|
||||||
var PAGES = { editor: "editor.html", initial: "player.html", teacher: "teacher.html",
|
var PAGES = { editor: "editor.html", kit: "kit.html", initial: "player.html", teacher: "teacher.html",
|
||||||
stage: "stage.html", micro: "micro.html", showcase: "showcase.html" };
|
stage: "stage.html", micro: "micro.html", showcase: "showcase.html" };
|
||||||
var me = document.currentScript;
|
var me = document.currentScript;
|
||||||
var ORIGIN = me ? me.src.replace(/\/embed\.js(\?.*)?$/, "") : location.origin;
|
var ORIGIN = me ? me.src.replace(/\/embed\.js(\?.*)?$/, "") : location.origin;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue